在回调中使用 $q - 这可能吗?
Using $q within a callback - is this possible?
我用下面的代码创建了一个简单的例子。目标是能够使用来自 Angular 的 $q
服务的 deferred
承诺,但在回调中有 $q
本身 return 的结果是在主控制器中处理。
我认识到错误显然是 $q
的承诺需要立即 returned 以便它可以 "await" 结果并将该承诺放在回调中禁止它立即被 returned。因此,下面的代码显然是一个错误的策略。
我的问题是要问最佳实践是什么来实现与上述愿望相当的效用,包括存在回调和需要 return 承诺。
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);
});
好吧,我真的想通了。您创建 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);
});
为了整合评论并解决其他答案对异步 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
是第 3 方 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);
});
我用下面的代码创建了一个简单的例子。目标是能够使用来自 Angular 的 $q
服务的 deferred
承诺,但在回调中有 $q
本身 return 的结果是在主控制器中处理。
我认识到错误显然是 $q
的承诺需要立即 returned 以便它可以 "await" 结果并将该承诺放在回调中禁止它立即被 returned。因此,下面的代码显然是一个错误的策略。
我的问题是要问最佳实践是什么来实现与上述愿望相当的效用,包括存在回调和需要 return 承诺。
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);
});
好吧,我真的想通了。您创建 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);
});
为了整合评论并解决其他答案对异步 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
是第 3 方 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);
});