【问题标题】:Using deferred promise inside for each loop using node.js使用 node.js 在每个循环中使用延迟承诺
【发布时间】:2015-03-16 12:55:32
【问题描述】:

当我在 node.js 的循环中使用 Promise 时遇到了问题。 下面是一个简单的例子,我正在使用cheerio 来抓取网页并执行以下操作:

$('.xyz').each(function(){
  fn1()
  .then(fn2)
  .then(fn3)    
});


function fn1() {
  var deferred = Q.defer();
  console.log("1");
  deferred.resolve();
  return deferred.promise;
}

function fn2() {
  var deferred = Q.defer();
  console.log("2");
  deferred.resolve();
  return deferred.promise;
}

function fn3() {
  var deferred = Q.defer();
  console.log("3");
  deferred.resolve();
  return deferred.promise;
}

我期待最终输出为 123123123,但我得到的是 111222333。有人可以解释为什么会这样。我对 node.js 很陌生,可以使用一些帮助。

【问题讨论】:

标签: node.js promise cheerio


【解决方案1】:

嗯,你确实是用三组链接你的 Promise,但是你是并行运行每个链,所以流程是这样的:

  1. 运行fn1(),安排fn2fn3 供以后使用。
  2. 再次运行fn1(),安排相同
  3. 再次运行fn1(),安排相同的时间
  4. fn2()s 运行之一
  5. 等等……

如果您希望它们按顺序运行,则需要将它们全部安排在同一个 Promise 对象上。

【讨论】:

    【解决方案2】:

    这是因为Q 将“then”回调安排到下一个滴答声(在承诺解决之后)。见source。 “Next tick”依次通过setImmediatesetTimeoutprocess.nextTick等方式实现,具体取决于您使用的平台(见source)。所有的 Promise 实现都保证 then 回调将在当前调用堆栈执行之后执行。可以通过向微任务队列(如v8引擎)或事件循环任务队列(例如使用setTimeout)添加回调来实现。如果您不了解事件循环任务队列的工作原理 - 请参阅 this video

    【讨论】:

    【解决方案3】:

    将 Promise 处理程序排队和重新声明 Promise 之间存在细微差别。考虑以下代码,它会产生您想要的行为,即 123123123:

    var a = Q();
    
    [1,2,3].forEach(function(){
      a = a.then(fn1)
        .then(fn2)
        .then(fn3);
    });
    
    
    function fn1() {
      var deferred = Q.defer();
      console.log("1");
      deferred.resolve();
      return deferred.promise;
    }
    
    function fn2() {
      var deferred = Q.defer();
      console.log("2");
      deferred.resolve();
      return deferred.promise;
    }
    
    function fn3() {
      var deferred = Q.defer();
      console.log("3");
      deferred.resolve();
      return deferred.promise;
    }
    

    (此处为JSBin:http://jsbin.com/hituzedare/2/edit?js,console

    现在考虑以下非常相似的示例,结果为 111222333。

    var a = Q();
    
    [1,2,3].forEach(function(){
      a.then(fn1)
        .then(fn2)
        .then(fn3);
    });
    
    
    function fn1() {
      var deferred = Q.defer();
      console.log("1");
      deferred.resolve();
      return deferred.promise;
    }
    
    function fn2() {
      var deferred = Q.defer();
      console.log("2");
      deferred.resolve();
      return deferred.promise;
    }
    
    function fn3() {
      var deferred = Q.defer();
      console.log("3");
      deferred.resolve();
      return deferred.promise;
    }
    

    (此处为JSBin:http://jsbin.com/hituzedare/1/edit?js,console

    关键是:第一个示例将变量重新定义为一个新的承诺 - 具体来说,fn3 返回的承诺。

    因此,在下一次 forEach 迭代中,promise 现在被链接到 fn3 的末尾,而不是顶部的 promise。

    我希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 2013-04-27
      • 2021-02-09
      • 2018-05-03
      • 1970-01-01
      • 2017-12-04
      • 1970-01-01
      • 2013-12-07
      • 1970-01-01
      • 2015-04-19
      相关资源
      最近更新 更多