我的应用程序有许多同步和异步(执行$ http调用)方法。在 控制器我有这样的代码:
$q.all([
asyncMethod1(),
syncMethod1()
])
.then(function (results) {
即使我没有必要等待syncMethod1(),我把它放在$ q.all里面以保持简单并允许我 如果我将来想要将方法更改为异步。
对于同步功能,我这样称呼它们:
var syncMethod1 = function () {
var defer = $q.defer();
var abc = 99;
defer.resolve({
data1: abc,
data2: 123
});
return defer.promise;
};
我想知道的是,如果有一种方法可以让同步方法返回$ q.all数据但没有我的 需要创建一个defer变量然后返回defer.promise?试着让同步方法变得简单 尽可能。
答案 0 :(得分:1)
$q.all
即使没有记录,也可以采用普通值,而不仅仅是promises(它会自动转换它们)。您的同步方法应该只是
return {
data1: 99,
data2: 123
};
这是最简单的事情(并且可以在真正的同步上下文中使用)。
如何在不使用繁琐的延迟的情况下从值中做出承诺?
您可以使用$q.when
:
return $q.when({
data1: 99,
data2: 123
});
如果该值不是承诺,则将返回一个尽快使用该值解析的承诺。请注意,这必然会在您的代码中引入异步,因此它不再是syncMethod
。
答案 1 :(得分:1)
TL; DR:是的,只需从同步方法返回正常值,并在$q.all
中将它们用作输入参数。它会正确处理它们。
答案很长
如果我们查看$q.all
的角度代码,我们会在this line看到输入参数的处理方式:
function all(promises) {
....
forEach(promises, function(promise, key) {
....
ref(promise).then(function(value) {
因此每个参数都传递给ref
函数defined at this line。 ref
接受一个参数,如果它是一个承诺它会返回它
if (value && isFunction(value.then)) return value;
如果不是,那么该值将被返回一个新创建的promise。该承诺会尽快解决,但不会在此事件循环迭代中解决。
return {
then: function(callback) {
var result = defer();
nextTick(function() {
result.resolve(callback(value));
});
return result.promise;
}
};
这意味着您可以安全地从同步方法返回非承诺值。
function asyncFirst() {
var def = $q.defer();
$timeout(function(){
$scope.first = true;
def.resolve();
}, 1000);
return def.promise;
}
function syncSecond() {
$scope.second = true;
return {
data1: 'abc',
data2: 123
};
}
$q.all([
asyncFirst(),
syncSecond()
])
.then(function(){
$scope.all = true;
});
中查看此操作
编辑:
正如用户@Bergi建议的那样,$q.when
source可以根据需要将任何常规值转换为承诺但是,$q.when
使用ref
函数将值转换为承诺并结算在下一个事件循环迭代中的承诺。严格地说,方法本身是同步的,因为它返回没有延迟。但结果立即包含在承诺中,直到下一个事件循环迭代才会被使用。这意味着同步方法不会这样使用。至少在大多数人不会想象同步方法。 $q.all
的总体结果将使用async这样的同步方法,但在下一次迭代中解决。考虑一下这个警告。
答案 2 :(得分:0)
如果你需要做更多的逻辑而不仅仅是返回值,并且你为很多同步函数做了一些事情,你可能想要创建一个为你做延迟逻辑的包装函数:
var makeAsync = function(fn){
return function(){
var deferred = $q.defer();
deferred.resolve(fn.apply(this,arguments));
return deferred.promise;
};
}
然后你可以这样做:
$q.all([
asyncMethod1(),
makeAsync(syncMethod1)()
])
.then(function (results) {