async / await与ES6的差异与发电机的比率

时间:2016-03-24 09:14:47

标签: javascript node.js ecmascript-6 generator ecmascript-next

我刚刚读了这篇精彩的文章 -

https://www.promisejs.org/generators/

它清楚地突出了这个函数,它是一个用于处理生成器函数的辅助函数:

function async(makeGenerator){
  return function () {
    var generator = makeGenerator.apply(this, arguments);

    function handle(result){
      // result => { done: [Boolean], value: [Object] }
      if (result.done) return Promise.resolve(result.value);

      return Promise.resolve(result.value).then(function (res){
        return handle(generator.next(res));
      }, function (err){
        return handle(generator.throw(err));
      });
    }

    try {
      return handle(generator.next());
    } catch (ex) {
      return Promise.reject(ex);
    }
  }
}

我假设或多或少是用async/await实现async关键字的方式。所以问题是,如果是这样的话,那么它的区别是什么呢? await关键字和yield关键字? await是否总是将某些内容转化为承诺,而yield却没有这样的保证?这是我最好的猜测!

你还可以看到async / await与本文中的生成器的yield相似,他描述了' spawn'功能:https://jakearchibald.com/2014/es7-async-functions/

6 个答案:

答案 0 :(得分:37)

yield可以被视为await的构建块。 yield获取它给出的值并将其传递给调用者。然后呼叫者可以用该值做任何他想做的事情(1)。稍后调用者可以将值返回给生成器(通过generator.next()),这将成为yield表达式(2)的结果,或者{{1}将出现的错误表达式(3)。

yield - async可以被视为使用await。在(1)调用者(即yield - async驱动程序 - 与您发布的函数类似)将使用与await类似的算法将值包装在promise中(注意,< em> not new Promise(r => r(value),但这并不是什么大不了的事。然后它等待承诺解决。如果它满足,则将完成的值传递回(2)。如果它拒绝,它会将拒绝原因作为错误抛出(3)。

所以Promise.resolve - async的效用就是这个机制使用await将生成的值解包为一个promise并将其解析后的值传回,重复直到函数返回其最终值值。

答案 1 :(得分:32)

嗯,事实证明,async / await和generator之间存在非常密切的关系。我相信async / await将永远建立在生成器上。如果你看看Babel变异async / await的方式:

Babel接受了这个:

this.it('is a test', async function () {

    const foo = await 3;
    const bar = await new Promise(resolve => resolve('7'));
    const baz = bar * foo;
    console.log(baz);

});

并将其转换为此

function _asyncToGenerator(fn) {
    return function () {
        var gen = fn.apply(this, arguments);
        return new Promise(function (resolve, reject) {
            function step(key, arg) {
                try {
                    var info = gen[key](arg);
                    var value = info.value;
                } catch (error) {
                    reject(error);
                    return;
                }
                if (info.done) {
                    resolve(value);
                } else {
                    return Promise.resolve(value).then(function (value) {
                        return step("next", value);
                    }, function (err) {
                        return step("throw", err);
                    });
                }
            }

            return step("next");
        });
    };
}


this.it('is a test', _asyncToGenerator(function* () {   // << now it's a generator

    const foo = yield 3;    //  <<< now it's yield, not await
    const bar = yield new Promise(resolve => resolve(7));
    const baz = bar * foo;
    console.log(baz);

}));

你做数学。

这使得async关键字看起来就像那个包装函数一样,但是如果是这样的情况那么await就会变成yield,那么稍后当它们变成native时可能会有更多的东西。

您可以在此处看到更多解释: https://www.promisejs.org/generators/

答案 2 :(得分:25)

  

await关键字和yield关键字之间的区别是什么?

await关键字仅用于async function,而yield关键字仅用于生成器function*。而且那些明显不同 - 一个返回承诺,另一个返回生成器。

  

await是否总是将某些内容转化为承诺,而yield没有做出这样的保证?

是的,await会在等待值上调用Promise.resolve

yield只会产生生成器之外的值。

答案 3 :(得分:4)

tldr;

在Generator上99%的时间使用异步/等待。为什么?

  1. Async / Await直接替换了最常见的承诺链工作流程,允许将代码声明为同步状态,从而大大简化了代码。

  2. 生成器对用例进行了抽象,其中您将调用一系列相互依赖的异步操作,最终将处于“完成”状态。最简单的例子是分页显示最终返回最后一组结果的结果,但是您只会根据需要调用页面,而不会立即连续调用该页面。

  3. Async / Await实际上是一种基于Generators的抽象,它使使用Promise更加容易。

See very in-depth Explanation of Async/Await vs. Generators

答案 4 :(得分:3)

尝试这个测试程序,我用它来理解await / async with promises

计划#1:没有承诺,它不会按顺序运行

function functionA() {
    console.log('functionA called');
    setTimeout(function() {
        console.log('functionA timeout called');
        return 10;
    }, 15000);

}

function functionB(valueA) {
    console.log('functionB called');
    setTimeout(function() {
        console.log('functionB timeout called = ' + valueA);
        return 20 + valueA;
    }, 10000);
}

function functionC(valueA, valueB) {

    console.log('functionC called');
    setTimeout(function() {
        console.log('functionC timeout called = ' + valueA);
        return valueA + valueB;
    }, 10000);

}

async function executeAsyncTask() {
    const valueA = await functionA();
    const valueB = await functionB(valueA);
    return functionC(valueA, valueB);
}
console.log('program started');
executeAsyncTask().then(function(response) {
    console.log('response called = ' + response);
});
console.log('program ended');

计划2:承诺:

function functionA() {
    return new Promise((resolve, reject) => {
        console.log('functionA called');
        setTimeout(function() {
            console.log('functionA timeout called');
            // return 10;
            return resolve(10);
        }, 15000);
    });   
}

function functionB(valueA) {
    return new Promise((resolve, reject) => {
        console.log('functionB called');
        setTimeout(function() {
            console.log('functionB timeout called = ' + valueA);
            return resolve(20 + valueA);
        }, 10000);

    });
}

function functionC(valueA, valueB) {
    return new Promise((resolve, reject) => {
        console.log('functionC called');
        setTimeout(function() {
            console.log('functionC timeout called = ' + valueA);
            return resolve(valueA + valueB);
        }, 10000);

    });
}

async function executeAsyncTask() {
    const valueA = await functionA();
    const valueB = await functionB(valueA);
    return functionC(valueA, valueB);
}
console.log('program started');
executeAsyncTask().then(function(response) {
    console.log('response called = ' + response);
});
console.log('program ended');

答案 5 :(得分:0)

在许多方面,生成器是async / await的超集。现在,async / await具有比co更清晰的堆栈跟踪,这是最流行的基于lib的async / await-like生成器。您可以使用生成器实现自己的async / await风格并添加新功能,例如对非承诺的yield的内置支持或在RxJS observables上构建它。

因此,简而言之,生成器为您提供了更大的灵活性,基于生成器的库通常具有更多功能。但async / await是该语言的核心部分,它是标准化的,并且在您之下不会发生变化,并且您不需要库来使用它。我有一个blog post,其中详细介绍了async / await和generator之间的区别。