Javascript async/await 和 ES6 生成器之间的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36196608/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 18:44:44  来源:igfitidea点击:

Difference between async/await and ES6 yield with generators

javascriptnode.jsecmascript-6generatorecmascript-next

提问by Alexander Mills

I was just reading this fantastic article ?Generators? and it clearly highlights this function, which is a helper function for handling generator functions:

我只是在读这篇精彩的文章?发电机?它清楚地突出显示了这个函数,它是一个处理生成器函数的辅助函数:

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

which I hypothesize is more or less the way the asynckeyword is implemented with async/await.So the question is, if that is the case, then what the heck is the difference between the awaitkeyword and the yieldkeyword? Does awaitalways turn something into a promise, whereas yieldmakes no such guarantee? That is my best guess!

我假设这或多或少是async关键字实现的方式async/ await所以问题是,如果是这样,那么await关键字和yield关键字之间到底有什么区别?是否await总是将某些东西变成承诺,而yield没有做出这样的保证?这是我最好的猜测!

You can also see how async/awaitis similar to yieldwith generators in this article where he describes the 'spawn' function ES7 async functions.

您还可以在本文中看到async/与生成器的await相似之处yield,他描述了“生成”函数ES7 异步函数

采纳答案by Alexander Mills

Well, it turns out that there is a very close relationship between async/awaitand generators. And I believe async/awaitwill always be built on generators. If you look at the way Babel transpiles async/await:

好吧,事实证明async/await和生成器之间有非常密切的关系。我相信async/await将始终建立在生成器上。如果你看看 Babel 转译async/的方式await

Babel takes this:

巴贝尔采取了这个:

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

});

and turns it into this

并把它变成这个

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

}));

you do the math.

你做数学。

This makes it look like the asynckeyword is just that wrapper function, but if that's the case then awaitjust gets turned into yield, there will probably be a bit more to the picture later on when they become native.

这使得async关键字看起来只是那个包装函数,但如果是这种情况,那么它await只是变成了yield,当它们成为本机时,可能会有更多的图片。

You can see more of an explanation for this here: https://www.promisejs.org/generators/

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

回答by Arnavion

yieldcan be considered to be the building block of await. yieldtakes the value it's given and passes it to the caller. The caller can then do whatever it wishes with that value (1). Later the caller may give a value back to the generator (via generator.next()) which becomes the result of the yieldexpression (2), or an error that will appear to be thrown by the yieldexpression (3).

yield可以被认为是await. yield获取它给定的值并将其传递给调用者。然后调用者可以使用该值 (1) 做任何想做的事情。稍后,调用者可能会将一个值返回给生成器(通过generator.next()),该值将成为yield表达式 (2)的结果,或者yield表达式 (3)会抛出一个错误。

async-awaitcan be considered to use yield. At (1) the caller (i.e. the async-awaitdriver - similar to the function you posted) will wrap the value in a promise using a similar algorithm to new Promise(r => r(value)(note, notPromise.resolve, but that's not a big deal). It then waits for the promise to resolve. If it fulfills, it passes the fulfilled value back at (2). If it rejects, it throws the rejection reason as an error at (3).

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

So the utility of async-awaitis this machinery that uses yieldto unwrap the yielded value as a promise and pass its resolved value back, repeating until the function returns its final value.

所以效用async-await是这款机器使用yield解开了产生价值的承诺,并通过其解析值回,重复,直到函数返回其最终值。

回答by Bergi

what the heck is the difference between the awaitkeyword and the yieldkeyword?

await关键字和yield关键字之间到底有什么区别?

The awaitkeyword is only to be used in async functions, while the yieldkeyword is only to be used in generator function*s. And those are obviously different as well - the one returns promises, the other returns generators.

await关键字仅在使用async functionS,而yield关键字是唯一的在发电机使用function*秒。这些显然也不同——一个返回承诺,另一个返回生成器。

Does awaitalways turn something into a promise, whereas yieldmakes no such guarantee?

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

Yes, awaitwill call Promise.resolveon the awaited value.

是的,await将调用Promise.resolve等待的值。

yieldjust yields the value outside of the generator.

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

回答by Jason Sebring

tl;dr

tl;博士

Use async/await99% of the time over generators.Why?

在发电机上使用async/ await99% 的时间。为什么?

  1. async/awaitdirectly replaces the most common workflow of promise chains allowing code to be declared as if it was synchronous, dramatically simplifying it.

  2. Generators abstract the use case where you would call a series of async-operations that depend on each other and eventually will be in a "done" state. The most simple example would be paging through results that eventually return the last set but you would only call a page as needed, not immediately in succession.

  3. async/awaitis actually an abstraction built on top of generators to make working with promises easier.

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

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

  3. async/await实际上是一个建立在生成器之上的抽象,使使用 promise 更容易。

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

查看 Async/Await vs. Generators 的非常深入的解释

回答by Kamal Kumar

Try this test programs which I used to understand await/asyncwith promises.

试试这个我曾经理解await/async承诺的测试程序。

Program #1: without promises it doesn't run in sequence

程序#1:没有promise,它不会按顺序运行

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

程序#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');

回答by vkarpov15

In many ways, generators are a superset of async/await. Right now async/await has cleaner stack traces than co, the most popular async/await-like generator based lib. You can implement your own flavor of async/await using generators and add new features, like built-in support for yieldon non-promises or building it on RxJS observables.

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

So, in short, generators give you more flexibility and generator-based libs generally have more features. But async/await is a core part of the language, it's standardized and won't change under you, and you don't need a library to use it. I have a blog postwith more details on the difference between async/await and generators.

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