【问题标题】:nodejs Q.all promises on function calling itselfnodejs Q.all 对函数调用自身的承诺
【发布时间】:2016-03-02 21:31:34
【问题描述】:

我需要发出一个请求来获取一个 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() 并创建第一个延迟变量
2 - 发出第一个请求并将第一个创建的延迟变量推送到 promises 数组
3 - Q.all 被调用并等待

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

假设这只深入了一层

8 - 第二个承诺已解决
9 - Q.all 调用它的回调

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

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

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

【问题讨论】:

  • Q.all被调用时,数组中只有一个promise,所以它只会等待这个promise被解析,即使数组被修改了。我没有时间发布完整的答案,但只有在解决所有子链接时才尝试解决父承诺。递归地传递承诺,它应该可以工作。
  • 但我不明白数组中只有一个承诺,JS 真的是同步的,只有 io 是异步的,下一个承诺应该在第一个 ome 解决之前添加,所以你说reguardless..它只会在它被调用时解决其中的那些..那男性感觉然后我猜......

标签: javascript node.js asynchronous promise q


【解决方案1】:

回答已编辑的问题:

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

【讨论】:

  • 这看起来不错,但我忘了在请求回调中添加循环,这个解决方案还能用吗?查看更新的示例。
  • @Ezra - 我相信我已经修改了答案以适应“新”问题
  • 你可以尝试只在最低级别进行承诺,并将递归调用和数组内容移动到单独的承诺回调中吗?
  • @Bergi - 查看代码,我确信可能有更优雅的解决方案,我什至不确定更新的答案是否有效(我通常会测试我的任何答案不是 100% 肯定,但这次我没有)
  • @Bergi - 再次编辑,不确定您是否是这个意思
猜你喜欢
  • 1970-01-01
  • 2018-05-18
  • 2018-01-31
  • 1970-01-01
  • 2016-03-04
  • 1970-01-01
  • 2014-02-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多