Разница между использованием ключевых слов 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
драйвер-похож на функцию, которую вы опубликовали) обернет значение в обещание, используя аналогичный алгоритм для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
ключевое слово?The
await
ключевое слово должно использоваться только вasync function
s, в то время какyield
ключевое слово должно использоваться только в генераторе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 и генераторами.