我刚刚读了这篇精彩的文章 -
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/
答案 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)
在Generator上99%的时间使用异步/等待。为什么?
Async / Await直接替换了最常见的承诺链工作流程,允许将代码声明为同步状态,从而大大简化了代码。
生成器对用例进行了抽象,其中您将调用一系列相互依赖的异步操作,最终将处于“完成”状态。最简单的例子是分页显示最终返回最后一组结果的结果,但是您只会根据需要调用页面,而不会立即连续调用该页面。
Async / Await实际上是一种基于Generators的抽象,它使使用Promise更加容易。
答案 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');
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之间的区别。