我用下面的代码创建了一个简单的例子。目标是能够使用Angular的deferred
服务中的$q
承诺,但在回调中有$q
,回调本身会返回要在主控制器中处理的结果。
我认识到错误显然是需要立即返回$q
的承诺,以便它可以“等待”结果,并且将该承诺放在回调中会阻止它立即返回。因此,下面的代码显然是一个不正确的策略。
我的问题是要问最佳实践是什么,以实现与上述愿望相当的效用,包括回调的存在和需要返回承诺。
function asyncGreet(name, cb) {
cb(name)
}
function okToGreet(name) {
return name.length > 10
}
var promise = asyncGreet('Robin Hood', function(name) {
var deferred = $q.defer();
setTimeout(function() {
deferred.notify('About to greet ' + name + '.');
if (okToGreet(name)) {
deferred.resolve('Hello, ' + name + '!');
} else {
deferred.reject('Greeting ' + name + ' is not allowed.');
}
}, 1000);
return deferred.promise;
});
promise.then(function(greeting) {
console.log('Success: ' + greeting);
}, function(reason) {
console.log('Failed: ' + reason);
});
答案 0 :(得分:2)
嗯,我真的想通了。您创建deferred
然后将其传递给回调。在我发布之前本应该对我很明显,但也许它会帮助那些像我一样感到困惑的其他人:
function asyncGreet(name, cb) {
var deferred = $q.defer();
setTimeout(function() {
var foo = null;
cb(name, deferred)
}, 1000);
return deferred.promise;
}
var promise = asyncGreet('Robin Hood', function(name, deferred) {
if (name.length > 10) {
foo = 'Hello, ' + name + '!';
} else {
foo = 'Greeting ' + name + ' is not allowed.';
}
deferred.resolve(foo);
});
promise.then(function(greeting) {
console.log('Success: ' + greeting);
}, function(reason) {
console.log('Failed: ' + reason);
});
答案 1 :(得分:2)
为了整合评论并解决其他答案对异步API的一些令人困惑的描述,我决定提供一个答案:
如果我们假设存在一些异步的非承诺/基于回调的API,例如asyncGreet
,则可以像下面那样进行模拟:
function asyncGreet(name, cb){
// simulate async
setTimeout(function(){
someCondition ? cb({message: "Hello, " + name + "!"}) :
cb({error: "Greeting " + name + " is not allowed."});
}, 2000);
}
(出于本示例的目的,asyncGreet
是第三方API 不在我们的控制中)
要将此转换为$q
基于承诺的API,您可以使用$q
(使用$q.defer
或$q
构造函数 - 实际上,我只是注意到了那Angular's documentation shows the $q
-constructor approach)。
因此,例如,您可以创建greeterSvc
服务:
app.factory("greeterSvc", function greeterSvcFactory($q){
return {
greet: function(name){
return $q(function(resolve, reject){
asyncGreet(name, function cb(data){
if ('error' in data) {
reject(data.error); // extract reason
} else {
resolve(data.message); // extract greeting message
}
});
});
}
}
})
greeterSvc.greet
API的消费者可以.then
,例如,记录某些内容 - 就像您一样(尽管我会改用.catch
)
greeterSvc.greet("Robin Hood")
.then(function(greeting) {
console.log('Success: ' + greeting);
})
.catch(function(reason) {
console.log('Failed: ' + reason);
});