Разница между выходом async/await и ES6 с генераторами
Я как раз читал эту фантастическую статью -
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 реализовано с async/await
. Итак, вопрос в том, если это так, то в чем, черт возьми, разница между await
ключевое слово и yield
ключевое слово? Делает await
всегда превращайте что-то в обещание, тогда как yield
не дает такой гарантии? Это мое лучшее предположение!
вы также можете увидеть, как async / await похож на yield с генераторами в этой статье, где он описывает функцию "spawn":https://jakearchibald.com/2014/es7-async-functions/
6 ответов
yield
можно считать строительным блоком await
. yield
принимает заданное значение и передает его вызывающему. Затем абонент может делать что угодно с этим значением (1). Позже вызывающий абонент может вернуть значение генератору (через generator.next()
), который становится результатом yield
выражение (2) или ошибка, которая будет отображаться как вызванная yield
выражение (3).
async
-await
можно использовать yield
. В (1) абонент (то есть async
-await
driver-аналогично функции, которую вы опубликовали) обернет значение в обещание, используя аналогичный алгоритм для new Promise(r => r(value)
(обратите внимание, не Promise.resolve
, но это не большая проблема). Затем он ждет, когда обещание разрешится. Если он выполняет, он передает выполненное значение обратно в (2). Если он отклоняет, он выбрасывает причину отклонения как ошибку в (3).
Итак, полезность async
-await
это оборудование, которое использует yield
развернуть дали значение как обещание и передать его разрешенное значение обратно, повторяя до тех пор, пока функция не вернет его конечное значение.
ну, оказывается, что существует очень тесная связь между async / await и генераторами. И я считаю, что async / await всегда будет построен на генераторах. Если вы посмотрите, как Babel транспилирует async / await:
Вавилон берет это:
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);
});
и превращает его в этот
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);
}));
вы делаете математику.
это делает его похожим на ключевое слово async-это просто функция обертки, но если это так, то await просто превращается в урожай, наверное, будет немного позже, когда они станут родными.
какого черта разница между
await
ключевое слово иyield
сайта?
на await
ключевое слово должно использоваться только в async function
s, в то время как yield
ключевое слово должно использоваться только в generator function*
s. И они, очевидно, тоже разные - один возвращает обещания, другой возвращает генераторы.
тут
await
всегда превращайте что-то в обещание, тогда какyield
не дает таких гарантия?
да await
будем называть Promise.resolve
о ожидаемом значении.
yield
просто дает значение вне генератора.
попробуйте эти тестовые программы, которые я использовал для понимания await / async с обещаниями
программа #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');
программа 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');
tldr;
используйте Async / Await 99% времени над генераторами. Почему?
Async / Await напрямую заменяет наиболее распространенный рабочий поток цепочек обещаний, позволяющий объявлять код как синхронный, что значительно упрощает его.
генераторы абстрактный вариант использования, когда вы вызываете серию асинхронных операций, которые зависят друг от друга и в конечном итоге будут в состоянии "готово". Самый простой примером может быть пролистывание результатов, которые в конечном итоге возвращают последний набор, но вы будете вызывать страницу только по мере необходимости, а не сразу подряд.
Async / Await на самом деле является абстракцией, построенной поверх генераторов, чтобы упростить работу с обещаниями.
см. очень подробное объяснение Async / Await против генераторов
во многих отношениях генераторы являются надмножеством async / await. Прямо сейчас async / await имеет более чистые трассировки стека, чем co, самый популярный асинхронный / ожидающий генератор на основе lib. Вы можете реализовать свой собственный аромат async / await с помощью генераторов и добавить новые функции, такие как встроенная поддержка yield
о не-обещаниях или построении его на наблюдаемых RxJS.
короче говоря, генераторы дают вам больше гибкости, а генераторные библиотеки обычно имеют больше функций. Но async / await является основной частью языка, он стандартизирован и не изменится под вами, и вам не нужна библиотека для его использования. У меня есть блоге С более подробной информацией о разнице между async / await и генераторами.