Разница между использованием ключевых слов 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 functions, в то время как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 и генераторами.