我需要发出一个请求来获取html列表,我需要扫描它并循环浏览它,并为找到的列表中的每一项发出更多请求,这些请求中可能有列表,依此类推,直到没有列表为止。
我需要一种方法来跟踪所有调用的请求,并在它们完成后调用另一个函数。棘手的是,对于HTML中的任何列表项,函数都会一遍又一遍地调用自己。
我遇到的问题是使用Q promise,它唯一等待的promise来自第一个请求,我不明白为什么假设节点像我认为的那样工作,请参阅代码:
var _ = require('underscore');
var request = require('request');
var allPromises = [];
var finalArray = [];
var start = function(id) {
var deferred = Q.defer();
request.get({
url: 'http://www.example.com/id/' + id
}, function() {
_.each(body.items, function(index) {
var item = this;
finalArray.push(item);
if(item.hasMore) {
start(item.id);
}
}
deferred.resolve();
});
allPromises.push(deferred.promise);
}
console.log('Starting');
start(1);
Q.all(allPromises).done(function (values) {
console.log('All Done');
});
我想发生的是:
第一次调用1-starts()并创建第一个延迟的var
2-发出第一个请求,并将第一个创建的延迟变量推送到promise数组
3-Q.all被调用并等待
4-调用第一个请求的回调5-如果请求包含body.x,则使用新id再次调用start()
6-创建并推送新的promise,并提出新的请求
7-第一个承诺被解决
假设这只深入一级
8-第二个承诺得到解决
9-Q.all调用其回调
但在实践中,Q.all在第一个promise之后调用回调,即使在第一个promise被解析之前推送了第二个promise,它也不会等待任何其他promise。
为什么?我该怎么做?
Update忘记在请求回调中添加循环。
编辑问题的答案:
var request = require('request');
var finalArray = [];
var start = function(id) {
var deferred = Q.defer();
request.get({
url: 'http://www.example.com/id/' + id
}, function() {
var subitems = [];
_.each(body.items, function(index) {
var item = this;
finalArray.push(item);
if(item.hasMore) {
subitems.push(start(item.id));
}
}
if (subitems.length) {
deferred.resolve(Q.all(subitems)); // resolve result of Q.all
} else {
deferred.resolve();
}
});
return deferred.promise;
}
start(1).done(function() {
console.log('All Done');
});
@Bergi码
var request = require('request');
var start = function(id) {
var deferred = Q.defer();
request.get({
url: 'http://www.example.com/id/' + id
}, function(err, body) {
if (err) deferred.reject(err);
else deferred.resolve(body);
});
return deferred.promise.then(function(body) {
var finalArray = [];
return Q.all(_.map(body.items, function(index) {
var item = this;
finalArray.push(item);
if(item.hasMore)
return start(item.id);
else
return [];
})).then(function(moreResults) {
return finalArray.concat.apply(finalArray, moreResults);
});
});
}
start(1).then(function(finalArray) {
console.log('All Done');
});