nodejs Q.all承诺函数调用自身

时间:2015-11-29 01:26:00

标签: javascript node.js asynchronous promise q

我需要提出一个获取html列表的请求,我需要扫描它并循环遍历它并为找到的列表中的每个项目发出更多请求,并且那些列表中可能包含列表,依此类推没有人离开。

我需要一种方法来跟踪所有被调用的请求,并在他们完成后调用另一个函数。棘手的一点就是函数会一遍又一遍地调用HTML中的任何列表项。

我遇到的问题是使用Q承诺它所等待的唯一承诺来自第一次请求,我无法理解为什么假设节点像我认为的那样工作,请参阅代码:

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 - 发出第一个请求,并将第一个创建的延迟变量推送到promises数组
3 - Q.all被调用并等待

4 - 调用第一个请求的回调 5 - 如果请求包含body.x,则使用新的id再次调用start() 6 - 创建并推送新的承诺并发出新的请求 7 - 第一个承诺得到解决

假设这只是一个深度

8 - 第二个承诺得到解决 9 - Q.all调用其回调

但实际上,Q.all在第一个承诺之后调用它的回调,即使第二个承诺在第一个承诺解决之前被推送,它也不会等待任何其他承诺。

为什么呢?我怎样才能做到这一点?

更新忘记在请求回调中添加循环。

1 个答案:

答案 0 :(得分:2)

回答编辑过的问题:

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');
});