如何使用生成器使promises同步执行

时间:2017-10-30 02:46:41

标签: javascript ecmascript-6 es6-promise

我在这里关注博客文章: http://www.tivix.com/blog/making-promises-in-a-synchronous-manner

表示生成器可用于同步承诺执行。

我知道这是一个不好的做法 - 我们正在使用类似GWT的框架(准确地说是Urweb),它现在只能理解同步的javascript函数返回值。

遵循该文章的代码

{
  'use strict';

  let asyncTask = () =>
    new Promise(resolve => {
      let delay = 1000;

      setTimeout(function () {
        resolve(delay);
      }, delay);
    });

  let makeMeLookSync = fn => {
    let iterator = fn();
    let loop = result => {
      !result.done && result.value.then(res =>
        loop(iterator.next(res)));
    };

    loop(iterator.next());
  };

  console.log(1);

  makeMeLookSync(function* () {
    let result = yield asyncTask();

    console.log(result);
  });

  console.log(3);
}

给出以下输出: 1 3 1000

但如果承诺是同步的,那么输出应该是

1 1000 3

我做错了吗?或者是不可能使用生成器同步承诺?

1 个答案:

答案 0 :(得分:2)

  

我做错了吗?

是。应该出现同步的所有代码都必须进入生成器函数:

makeMeLookSync(function* () {
  let result = yield asyncTask();

  console.log(result);
  console.log(3);
});
  

或者是否不可能使用生成器同步承诺?

您可以永远使异步代码同步。生成器允许您编写看起来同步的代码,这意味着(并且在您链接的文章中提到)代码从上到下执行:

  

尽可能简单地说:async JavaScript在读取时不执行 - 从上到下。

但是,如上所述,这只适用于发电机内部。 yield关键字允许您以同步方式编写代码。请注意,该函数的名称为makeMeLookSync,而不是makeMeSync

话虽如此,ES2017引入了async functions基本上做同样的事情,没有生成器和跑步者来执行生成器:

{
  'use strict';

  let asyncTask = () =>
    new Promise(resolve => {
      let delay = 1000;

      setTimeout(function() {
        resolve(delay);
      }, delay);
    });


  console.log(1);

  (async function() {
    let result = await asyncTask();
    console.log(result);
    console.log(3);
  }());
}