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

问题描述 投票:61回答:6

我刚读这篇精彩的文章 -

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/

javascript node.js ecmascript-6 generator ecmascript-next
6个回答
37
投票

yield可以被认为是await的基石。 yield获取它给出的值并将其传递给调用者。然后呼叫者可以用该值做任何他想做的事情(1)。之后,调用者可以将值返回给生成器(通过generator.next()),这将成为yield表达式(2)的结果,或者是由yield表达式(3)引发的错误。

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

所以async-await的效用就是这种机制,它使用yield将产生的值展开为一个承诺并将其解析后的值传回,重复直到函数返回其最终值。


32
投票

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

巴贝尔认为:

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,那么稍后当它们变成本机时可能还会有更多的东西。

你可以在这里看到更多的解释:https://www.promisejs.org/generators/


25
投票

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

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

await总是将某些东西变成一个承诺,而yield没有做出这样的保证吗?

是的,await将把Promise.resolve称为期待值。

yield只是产生发电机外的值。


5
投票

tldr;

使用Async / Await 99%的时间比生成器。为什么?

  1. Async / Await直接替换了最常见的promise链工作流,允许将代码声明为同步,从而大大简化了代码链。
  2. 生成器抽象用例,您将调用一系列依赖于彼此的异步操作,最终将处于“完成”状态。最简单的示例是分页结果,最终返回最后一组,但您只需要根据需要调用页面,而不是立即连续调用。
  3. Async / Await实际上是一个构建在Generators之上的抽象,可以更轻松地处理promises。

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


3
投票

试试这个测试程序,我曾经用它来理解await / async和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');

program 2 : with promises :

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

0
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.