Q.all() 的 then() 未被调用
then() for Q.all() not being called
在 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();
已发出所有请求,但我没有看到 "done" 打印到控制台。 promises
变量确实是一个promises列表,都已经"resolved"了,但是then
函数没有被调用。有什么想法吗?
您遇到了范围界定问题。您的变量 deferred
是整个函数的本地变量,而不仅仅是 for
循环,因此您在回调中使用它之前在循环中覆盖该变量,因此您不会解析所有延迟您创建的对象。请记住,回调会在 for
循环完全 运行 之后的某个时间发生。
一个简单的解决方法是更改为使用 let
而不是 var
。这将使您的 deferred
变量局部于 for
循环范围而不是整个函数范围。
但是,我的首选解决方法是制作 request()
的承诺版本,returns 承诺并使用它。
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
库 returns 是 request
库的替代品。你也可以使用它。
注意,假设 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);
}
编辑 2020 年 1 月 - request() 模块处于维护模式
仅供参考,request
模块及其衍生产品,例如 request-promise
are now in maintenance mode and will not be actively developed to add new features. You can read more about the reasoning here. There is a list of alternatives in this table with some discussion of each one. I have been using got()
我自己,它是从一开始就使用 promises 构建的,并且易于使用。
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);
}
所以基本上,您有一系列正在等待的未决承诺,其中只有最后一个被解决,因为其余的都在范围内丢失。
解决方案
- ES6
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);
}
附录
,你需要在你的回调中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);
}
在 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();
已发出所有请求,但我没有看到 "done" 打印到控制台。 promises
变量确实是一个promises列表,都已经"resolved"了,但是then
函数没有被调用。有什么想法吗?
您遇到了范围界定问题。您的变量 deferred
是整个函数的本地变量,而不仅仅是 for
循环,因此您在回调中使用它之前在循环中覆盖该变量,因此您不会解析所有延迟您创建的对象。请记住,回调会在 for
循环完全 运行 之后的某个时间发生。
一个简单的解决方法是更改为使用 let
而不是 var
。这将使您的 deferred
变量局部于 for
循环范围而不是整个函数范围。
但是,我的首选解决方法是制作 request()
的承诺版本,returns 承诺并使用它。
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
库 returns 是 request
库的替代品。你也可以使用它。
注意,假设 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);
}
编辑 2020 年 1 月 - request() 模块处于维护模式
仅供参考,request
模块及其衍生产品,例如 request-promise
are now in maintenance mode and will not be actively developed to add new features. You can read more about the reasoning here. There is a list of alternatives in this table with some discussion of each one. I have been using got()
我自己,它是从一开始就使用 promises 构建的,并且易于使用。
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);
}
所以基本上,您有一系列正在等待的未决承诺,其中只有最后一个被解决,因为其余的都在范围内丢失。
解决方案
- ES6
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);
}
附录
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);
}