我正在开发AngularJS应用程序并发现以下行为。
我的服务中有两个功能。第一个函数返回存储在数据库中的所有类别,第二个函数按其id返回一个类别。
这是我的服务:
angular.module('categoriesRepository', [])
.service('categoriesRepository', ['$cordovaSQLite', 'sqliteHelper',
function ($cordovaSQLite, sqliteHelper) {
//this works - returns an array with all categories
this.getAll = function () {
var categories = [];
$cordovaSQLite.execute(sqliteHelper.getDb(),
"SELECT * FROM categories;")
.then(function (res) {
for (var i = 0; i < res.rows.length; i++) {
categories.push(res.rows[i]);
}
});
return categories;
}
//this works not - returns undefined
this.getById = function (id) {
var category;
$cordovaSQLite.execute(sqliteHelper.getDb(),
"SELECT * FROM categories WHERE id = ?;", [id])
.then(function (res) {
category = res.rows[0];
});
return category;
}
}]);
我知道我可以使用Angulars $ q异步运行函数,并在完成处理时使用它们的值。
为什么getById函数直接返回类别而getAll会等到数组被填满?
修改
我发布了错误的getAll函数。 $ cordovaSQLite.execute
之前没有返回语句答案 0 :(得分:2)
<强>更新: - 强> 您的问题更新后。
在第一个示例中,您首先通过执行var categories = [];
创建数组,然后在完成异步调用之前返回此数组。异步调用完成后,只需将某些元素推入数组,因此不会破坏对数组(categories)变量的引用。如果你将调试它返回它,你会发现该函数返回一个空数组,稍后当异步调用成功时,数组将被填充。
在第二个示例中,您只创建一个变量,然后在异步调用完成之前返回它。但是,异步调用完成后,您将变量赋值给新值。从而摧毁了之前的参考文献。
<强>解决方案: - 强> 虽然不是一种让它有效的优先方法。您将不得不维护类别变量引用。为此,您可以使用angular.copy或angular extend
所以代码的第二部分应该是这样的 this.getById = function(id){ var category;
$cordovaSQLite.execute(sqliteHelper.getDb(),
"SELECT * FROM categories WHERE id = ?;", [id])
.then(function (res) {
angular.copy(res.rows[0], category);
//now the reference to the category variable
//will not be lost
});
return category;
}
更好的实践: - 你开发这个应用程序的方式是错误的。异步调用不应该以这种方式处理。我之前提出了一个问题,只是为了澄清在角度应用程序,工厂和控制器please have a look here内处理异步调用和状态的方法。它提供了两种处理状态和异步调用的方法。可能会有更多的实践,但这两个最适合我。
答案 1 :(得分:2)
不幸的是,这种方法出现来工作&#39;因为它是由修改返回的数组对象&#34;在某个未指定的时间&#34;在之后返回。
在 1 1 之后,在异步调用中修改了访问/观察的数组。这使得它似乎只能正常运行 ,因为(意外)异步 - 晚于观察。
如果观察是在实际完成SQLite操作之前 - 例如在getAll
函数调用之后立即执行 - 它将显示空数组。
两个函数都写得不正确,第一个意外releases Zalgo(或许是他的兄弟姐妹)。
有关详细信息,请参阅How do I return the response from an asynchronous call?。
1 Chrome的console.log可能会让人感到困惑,因为它像console.dir一样工作,因此可能会显示当前值,而不是显示的值被援引。
答案 2 :(得分:1)
如上所述,这是一种糟糕的做法。返回后不能立即使用函数的结果。
但是,我没有看到您确切问题的答案:为什么他们的行为不同?
这是因为使用数组返回对象的引用(类型为Array)。稍后您使用相同的引用来修改对象的内容,即将新项目推送到数组中。
但是在第二个函数中,您可以修改引用本身。你让局部变量categories
指向一个新对象。因此,旧对象(返回到外部范围的引用)保持不变。使它的工作方式与你应该写的相同
category.row = res.rows[0];
答案 3 :(得分:0)
在第一种情况下返回执行结果,而在第二种情况下返回该变量,该变量很可能尚未填充。