I was just reading this fantastic article -
我正在读这篇神奇的文章
https://www.promisejs.org/generators/
https://www.promisejs.org/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 async keyword is implemented with async/await
. So the question is, if that is the case, then what the heck is the difference between the await
keyword and the yield
keyword? Does await
always turn something into a promise, whereas yield
makes no such guarantee? That is my best guess!
我假设异步关键字是用async/ wait实现的。问题是,如果是这样,那么wait关键字和yield关键字之间到底有什么区别呢?等待总是把某物变成承诺,而收益却没有这样的保证吗?这是我最好的猜测!
You can also see how async/await is similar to yield with generators in this article where he describes the 'spawn' function: https://jakearchibald.com/2014/es7-async-functions/
在本文中,您还可以看到异步/ wait与生成器的产量类似,在本文中,他描述了“衍生”函数:https://jakearchibald.com/2014/es7-async-functions/
5 个解决方案
#1
31
yield
can be considered to be the building block of await
. yield
takes 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 yield
expression (2), or an error that will appear to be thrown by the yield
expression (3).
收益率可以被认为是等待的基础。yield取其给定的值并将其传递给调用者。然后调用者可以用这个值(1)做它想做的任何事情,稍后调用者可以将一个值返回给生成器(通过generator.next()),它将成为yield表达式(2)的结果,或者是yield表达式(3)抛出的错误。
async
-await
can be considered to use yield
. At (1) the caller (i.e. the async
-await
driver - similar to the function you posted) will wrap the value in a promise using a similar algorithm to new Promise(r => r(value)
(note, not Promise.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).
异步等待可以考虑使用yield。在(1)调用方(即异步等待驱动程序——类似于您所发布的函数)将使用与new promise相似的算法(r => r(value))(注意,不是promise)将该值封装在一个承诺中。决心,但这不是什么大问题)。然后等待承诺的解决。如果它满足,它会将满足的值返回到(2)。如果它拒绝,它会将拒绝原因作为错误抛出到(3)。
So the utility of async
-await
is this machinery that uses yield
to unwrap the yielded value as a promise and pass its resolved value back, repeating until the function returns its final value.
因此,异步等待的效用就是这个机器,它使用yield来作为承诺,并将其解析后的值返回,直到函数返回其最终值。
#2
25
Well, it turns out that there is a very close relationship between async/await and generators. And I believe async/await will always be built on generators. If you look at the way Babel transpiles async/await:
实际上,异步/等待和生成器之间存在着非常密切的关系。我相信异步/等待将永远建立在生成器上。如果你看看Babel的异步传输方式:
Babel takes this:
巴别塔需要:
this.it('is a test', async function () {
const foo = await 3;
const bar = await new Promise(function (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(function (resolve) {
resolve('7');
});
const baz = bar * foo;
console.log(baz);
}));
you do the math.
你自己算吧。
This makes it look like the async keyword is just that wrapper function, but if that's the case then await just gets turned into yield, there will probably be a bit more to the picture later on when they become native.
这让它看起来像是async关键字就是那个包装函数,但是如果是这样的话,等待就会变成yield,当它们变成native之后,可能会有更多的东西。
#3
22
what the heck is the difference between the
await
keyword and theyield
keyword?等待关键字和yield关键字之间的区别是什么?
The await
keyword is only to be used in async function
s, while the yield
keyword is only to be used in generator function*
s. And those are obviously different as well - the one returns promises, the other returns generators.
wait关键字仅用于异步函数,而yield关键字仅用于生成器函数*s。它们也明显不同——一个返回承诺,另一个返回生成器。
Does
await
always turn something into a promise, whereasyield
makes no such guarantee?等待总是把某物变成承诺,而收益却没有这样的保证吗?
Yes, await
will call Promise.resolve
on the awaited value.
是的,等待威尔呼唤承诺。决定等待的价值。
yield
just yields the value outside of the generator.
收益率只是产生发电机外部的价值。
#4
2
Try this test programs which I used to understand await/async with promises
尝试这个测试程序,我曾经理解等待/异步与承诺
Program #1 : without promises it doesn't run in sequence
程序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');
#5
0
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 yield
on non-promises or building it on RxJS observables.
在许多方面,生成器是异步/等待的超集。目前,异步/ waiting比最流行的基于async/await-like generator的lib有更清晰的堆栈跟踪。
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 post with more details on the difference between async/await and generators.
因此,简而言之,生成器提供了更多的灵活性,基于生成器的libs通常具有更多的特性。但是异步/ wait是语言的核心部分,它是标准化的,在您的操作下不会改变,您不需要一个库来使用它。我有一个博客文章,上面有更多关于异步/等待和生成器的区别的细节。
#1
31
yield
can be considered to be the building block of await
. yield
takes 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 yield
expression (2), or an error that will appear to be thrown by the yield
expression (3).
收益率可以被认为是等待的基础。yield取其给定的值并将其传递给调用者。然后调用者可以用这个值(1)做它想做的任何事情,稍后调用者可以将一个值返回给生成器(通过generator.next()),它将成为yield表达式(2)的结果,或者是yield表达式(3)抛出的错误。
async
-await
can be considered to use yield
. At (1) the caller (i.e. the async
-await
driver - similar to the function you posted) will wrap the value in a promise using a similar algorithm to new Promise(r => r(value)
(note, not Promise.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).
异步等待可以考虑使用yield。在(1)调用方(即异步等待驱动程序——类似于您所发布的函数)将使用与new promise相似的算法(r => r(value))(注意,不是promise)将该值封装在一个承诺中。决心,但这不是什么大问题)。然后等待承诺的解决。如果它满足,它会将满足的值返回到(2)。如果它拒绝,它会将拒绝原因作为错误抛出到(3)。
So the utility of async
-await
is this machinery that uses yield
to unwrap the yielded value as a promise and pass its resolved value back, repeating until the function returns its final value.
因此,异步等待的效用就是这个机器,它使用yield来作为承诺,并将其解析后的值返回,直到函数返回其最终值。
#2
25
Well, it turns out that there is a very close relationship between async/await and generators. And I believe async/await will always be built on generators. If you look at the way Babel transpiles async/await:
实际上,异步/等待和生成器之间存在着非常密切的关系。我相信异步/等待将永远建立在生成器上。如果你看看Babel的异步传输方式:
Babel takes this:
巴别塔需要:
this.it('is a test', async function () {
const foo = await 3;
const bar = await new Promise(function (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(function (resolve) {
resolve('7');
});
const baz = bar * foo;
console.log(baz);
}));
you do the math.
你自己算吧。
This makes it look like the async keyword is just that wrapper function, but if that's the case then await just gets turned into yield, there will probably be a bit more to the picture later on when they become native.
这让它看起来像是async关键字就是那个包装函数,但是如果是这样的话,等待就会变成yield,当它们变成native之后,可能会有更多的东西。
#3
22
what the heck is the difference between the
await
keyword and theyield
keyword?等待关键字和yield关键字之间的区别是什么?
The await
keyword is only to be used in async function
s, while the yield
keyword is only to be used in generator function*
s. And those are obviously different as well - the one returns promises, the other returns generators.
wait关键字仅用于异步函数,而yield关键字仅用于生成器函数*s。它们也明显不同——一个返回承诺,另一个返回生成器。
Does
await
always turn something into a promise, whereasyield
makes no such guarantee?等待总是把某物变成承诺,而收益却没有这样的保证吗?
Yes, await
will call Promise.resolve
on the awaited value.
是的,等待威尔呼唤承诺。决定等待的价值。
yield
just yields the value outside of the generator.
收益率只是产生发电机外部的价值。
#4
2
Try this test programs which I used to understand await/async with promises
尝试这个测试程序,我曾经理解等待/异步与承诺
Program #1 : without promises it doesn't run in sequence
程序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');
#5
0
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 yield
on non-promises or building it on RxJS observables.
在许多方面,生成器是异步/等待的超集。目前,异步/ waiting比最流行的基于async/await-like generator的lib有更清晰的堆栈跟踪。
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 post with more details on the difference between async/await and generators.
因此,简而言之,生成器提供了更多的灵活性,基于生成器的libs通常具有更多的特性。但是异步/ wait是语言的核心部分,它是标准化的,在您的操作下不会改变,您不需要一个库来使用它。我有一个博客文章,上面有更多关于异步/等待和生成器的区别的细节。