在Node.js中,我在进行函数调用之前等待几个请求完成,如下所示:
function loadQuotes(symbols){
var promises = [];
for(var s in symbols){
var deferred = Q.defer();
var url = rootURL;
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body);
deferred.resolve();
console.log("resolved");
}
});
promises.push(deferred.promise);
}
return Q.all(promises);
}
我正在等待以下所有请求
loadQuotes(symbols.slice(0,3)).then(function(data){
console.log("done");
httpServer();
}).done();
所有请求都已完成,但我看不到"已完成"打印到控制台。 promises
变量确实是一个承诺列表,它们都被解析了#34;但是then
函数没有被调用。有什么想法吗?
答案 0 :(得分:3)
你有一个范围问题。您的变量deferred
对于整个函数是本地的,而不仅仅是for
循环,因此在回调中使用它之前,您将覆盖循环中的变量,因此您不会解析所有延迟你创建的对象。请记住,回调是在for
循环完全运行之后的某个时间发生的。
一个简单的解决方法是更改为使用let
而不是var
。这将使deferred
变量成为for
循环范围的本地变量,而不是整个函数范围。
但是,我首选的修复方法是制作一个request()
的宣传版,它会返回一个承诺并使用它。
function rp(url) {
return new Promise(function(resolve, reject) {
request(url, function(err, response, body) {
if (err) return reject(err);
if (response.statusCode !== 200) reject(new Error(response.statusCode));
resolve(body);
});
});
}
然后,您可以使用它:
function loadQuotes(symbols){
var promises = [];
for(var s in symbols){
var url = rootURL;
promises.push(rp(url));
}
return Promise.all(promises);
}
或者,如果你真的需要使用Q库,你也可以使用它来编写上面的代码。
仅供参考,有一个request-promise
库可以返回一个代替request
库的promise。你也可以使用它。
注意,假设symbols
是一个数组,并且您希望坚持使用ES5解决方案,您也可以将for
循环切换为使用.forEach()
,这将创建一个新函数每次调用循环的范围,也解决了你的问题。
function loadQuotes(symbols){
var promises = [];
symbols.forEach(function(s) {
var deferred = Q.defer();
var url = rootURL;
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body);
deferred.resolve(info);
console.log("resolved");
}
});
promises.push(deferred.promise);
});
return Q.all(promises);
}
答案 1 :(得分:1)
var
不使用词法范围function loadQuotes(symbols){
var promises = [];
for(var s in symbols){
// here you declare `deferred` using `var`
var deferred = Q.defer();
var url = rootURL;
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body);
// this is called *later*
// when it is overwritten
// with the last value
// for every iteration
deferred.resolve();
console.log("resolved");
}
});
// here, you expect it to be resolved later
promises.push(deferred.promise);
}
return Q.all(promises);
}
所以基本上,你有一系列正在等待的未决承诺,其中只有最后一个承诺得到解决,因为其余的承诺在范围内丢失。
let
救援function loadQuotes(symbols){
var promises = [];
for(var s in symbols){
let deferred = Q.defer();
var url = rootURL;
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body);
deferred.resolve();
console.log("resolved");
}
});
promises.push(deferred.promise);
}
return Q.all(promises);
}
.bind()
您的匿名回调函数function loadQuotes(symbols){
var promises = [];
for(var s in symbols){
var deferred = Q.defer();
var url = rootURL;
request(url, function (deferred, error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body);
deferred.resolve();
console.log("resolved");
}
}.bind(null, deferred));
promises.push(deferred.promise);
}
return Q.all(promises);
}
As was pointed out by @Karl-Johan Sjögren,当出现错误时,您需要在回调中deferred.reject(error)
,否则Q.all()
将永远不会解决,并且您的应用程序会在出现问题时挂起,而不是响应正常。
要说清楚,我并不是说这会导致问题,但如果你不这样做会产生问题。总结一下:
function loadQuotes(symbols){
var promises = [];
for(var s in symbols){
var deferred = Q.defer();
var url = rootURL;
request(url, function (deferred, error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body);
// pass something meaningful here
deferred.resolve(info);
console.log("resolved");
} else {
// always reject errors when they occur
deferred.reject(error);
}
}.bind(null, deferred));
promises.push(deferred.promise);
}
return Q.all(promises);
}