【问题标题】:How to wait on completion of a whole chain of Promises in Javascript ECMAScript2015 (es6)如何在 Javascript ECMAScript2015 (es6) 中等待整个 Promise 链的完成
【发布时间】:2015-08-27 10:03:55
【问题描述】:

对 es6 还很陌生,很想知道现在是否可以使用 Promises,我可以取消 future.wait()

我有一个名为execute() 的方法,它启动了一系列承诺。我对这种方法有两个要求:

  • 每个promise 应该只在最后一个promise 完成后开始(这部分我已经实现了)
  • execute() 应该只在整个 Promise 链完成执行时返回(即我想阻塞直到最后一个 Promise 完成)

这是我的示例代码:

/* Require dependencies */
require('babel/polyfill');

class PromiseWaiter {
  /* Constructor */
  constructor() {
  }

  /* Methods */
  execute() {
    let _this = this;

    runPromiseGenerator(function *promiseGenerator() {
      yield _this.asyncMethod1();
      yield _this.asyncMethod2();
      yield _this.asyncMethod3();
    });

    return true;
  }

  asyncMethod1() {
    return returnDummyPromise('method 1', 800);
  }
  asyncMethod2() {
    return returnDummyPromise('method 2', 200);
  }
  asyncMethod3() {
    return returnDummyPromise('method 3', 200);
  }
}

var runPromiseGenerator = function(generator) {
  var it = generator(), ret;

  // asynchronously iterate over generator
  (function iterate(val) {
    ret = it.next(val);

    if (!ret.done) {
      // poor man's "is it a promise?" test
      if ("then" in ret.value) {
        // wait on the promise
        ret.value.then(iterate);
      }
      // immediate value: just send right back in
      else {
        // avoid synchronous recursion
        setTimeout( function(){
          iterate(ret.value);
        }, 0);
      }
    }
  })();

};

var returnDummyPromise = function(methodName, timeout) {
  console.log('starting %s', methodName);
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      console.log('finished %s', methodName);
      resolve();
    }, timeout);
  })
};

module.exports = PromiseWaiter;

这是我在节点控制台上运行的测试和当前输出:

> p = new PromiseWaiter()
{}
> p.execute()
starting method 1
true
> finished method 1
starting method 2
finished method 2
starting method 3
finished method 3

我想看到的是:

> p = new PromiseWaiter()
{}
> p.execute()
starting method 1
finished method 1
starting method 2
finished method 2
starting method 3
finished method 3
true
>

过去我会使用

fut = new Future();
// set off chain passing future
future.wait();

想挑选最优秀、最聪明的人。

提前感谢您的宝贵时间! 艾略特

【问题讨论】:

  • 为什么要重新实现runPromiseGeneratorco 已经做到了,它使用代码来处理您正在尝试做的事情。你需要runPromiseGenerator 来返回一个承诺,所以你可以做runPromiseGenerator(...).then(function(){ console.log('all done'); });
  • future.wait() 是什么东西?纤维?你在使用某个特定的库吗?

标签: javascript concurrency ecmascript-6


【解决方案1】:

您需要返回一个承诺,该承诺将在生成器完成后解决。我真的推荐使用像 co 这样的现有实现,但是如果你想扩展自己的实现:

var runPromiseGenerator = function(generator) {
  return new Promise(function(resolve, reject){
    var it = generator(), ret;

    // asynchronously iterate over generator
    (function iterate(val) {
      try {
        ret = it.next(val);

        if (!ret.done) {
          Promise.resolve(ret.value).then(iterate, reject);
        }
        else {
          resolve(ret.value);
        }
      }
      catch (e){
        reject(e);
      }
    })();
  });
};

然后您可以将您的execute 更改为

execute() {
  let _this = this;

  return runPromiseGenerator(function *promiseGenerator() {
    yield _this.asyncMethod1();
    yield _this.asyncMethod2();
    yield _this.asyncMethod3();
  });
}

然后做

p.execute().then(function(){
  // done
});

或者,您可以使用现有函数然后调用它,例如

runPromiseGenerator(function *promiseGenerator() {
  yield p.execute();

  // do something after execution
});

【讨论】:

  • 感谢您指导我 co - 正如我所说,我对 es6 还很陌生,还没有看过那个库。我理解你的建议,回报一个承诺,但这不是我想要的。我正在寻找一种方法来阻止执行完成,直到承诺链完成。我想我在 es7 的 await 关键字之后
  • 没问题,希望这一切都有意义。
  • 在 JS 中无法阻止执行,但您可以使用 yieldawait 之类的语法来暂停执行。如果您想在execute 之后执行某些操作,那么您必须使用runPromiseGeneratorco,就像您已经在做的那样。我在答案中添加了一个示例。 ES7 提议的 async/await 基本上与您在此处使用生成器实现的完全一样,只是使用了不需要外部库的新语法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-15
  • 2019-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多