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

Ale*_*lls 69 javascript generator node.js ecmascript-6 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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我假设或多或少是async关键字的实现方式async.所以问题是,如果是这种情况,那么async关键字和await关键字之间的区别是什么呢?是否await总是把东西放到一个承诺,而yield没有这样的保证?这是我最好的猜测!

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

Arn*_*ion 38

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

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

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

  • 检查这个答案/sf/answers/2756891231/,它与这个论点相矛盾。async-await 看起来与 Yield 类似,但它在底层使用了 Promise 链。如果您有任何好的资源说“async-await可以考虑使用yield”,请分享。 (2认同)
  • 我不确定你如何认为这个答案“与这个论点相矛盾”,因为它说的是与这个答案相同的事情。>与此同时,像 Babel 这样的转译器允许您编写 async/await 并将代码转换为生成器。 (2认同)
  • 这个答案并没有声称全世界所有的 ES 引擎都使用生成器在内部实现 Promise。有些可能;有些可能不会;这与所回答的问题无关。尽管如此,可以使用发电机以特定的方式驱动发电机来理解承诺工作的方式,这就是这个答案所解释的。 (2认同)

Ale*_*lls 35

嗯,事实证明,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);

});
Run Code Online (Sandbox Code Playgroud)

把它变成这个

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

}));
Run Code Online (Sandbox Code Playgroud)

你做数学.

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

  • 我不这么认为。Async/await 是在 V8 引擎中原生实现的。ES6 特性的生成器,async/await 是 ES7。它是 V8 引擎 5.5 版本的一部分(在 Node 中使用):https://v8project.blogspot.nl/2016/10/v8-release-55.html。可以将 ES7 async/await 转译为 ES6 生成器,但在新版本的 NodeJS 中不再需要这样做,而且 async/await 的性能甚至似乎比生成器更好:https://medium.com/@markherhold /generators-vs-async-await-performance-806d8375a01a (4认同)
  • NodeJS 有一段时间的原生 async/await,没有生成器:https://codeforgeek.com/2017/02/asyncawait-function-officially-shipped-nodejs-7-6-0/ (3认同)
  • 据我所知,V8 中的简短版本是“某种程度上”。是的,异步是使用生成器机制编写的:请参阅[此评论](https://github.com/v8/v8/blob/17a99fec258bcc07ea9fc5e4fabcce259751db03/src/builtins/builtins-async-function-gen.cc#L247-L254),但据我所知,他们正在使用内部 API 并专门使用 bulitin impls 来跳过不必要的检查 - 大概是因为您没有生成器对象的句柄来执行邪恶的操作。 (3认同)
  • @Bram本机实现绝对使用引擎下的引擎,同样的东西,只是抽象了. (2认同)
  • async/await 使用生成器来做它的事情 (2认同)
  • @AlexanderMills 你能分享一些合法的资源吗?这些资源说 async/await 在内部使用生成器?检查这个 ans stackoverflow.com/a/39384160/3933557 这与这个论点相矛盾。我认为,仅仅因为 Babel 使用生成器,并不意味着它在底层的实现类似。对此有任何想法 (2认同)

Ber*_*rgi 26

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

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

是否await总是把东西放到一个承诺,而yield没有这样的保证?

是的,await会打电话Promise.resolve给等待的价值.

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

  • `var r = await p; console.log(r);`应该转换为类似:`p.then(console.log);`,而`p`可能被创建为:`var p = new Promise(resolve => setTimeout(resolve, 1000,42));`,所以说"await _calls_ Promise.resolve"是错误的,它是一些完全远离'await'表达式的其他代码调用`Promise.resolve`,所以转换后的`await`表达式,即`Promise.then(console.log)`将被调用并打印出'42`. (2认同)

Jas*_*ing 8

tl; dr

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

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

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

  3. async/ await实际上是建立在生成器之上的抽象,以使兑现承诺更加容易。

深入了解Async / Await与生成器的说明


Kam*_*mar 5

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

程序#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');
Run Code Online (Sandbox Code Playgroud)

程序#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');
Run Code Online (Sandbox Code Playgroud)