Я только что читал эту фантастическую статью « Генераторы », и в ней четко освещается эта функция, которая является вспомогательной функцией для обработки функций генератора:
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
генераторы в этой статье, где он описывает функцию « порождения» асинхронных функций ES7 .
javascript
node.js
ecmascript-6
generator
ecmascript-next
Александр Миллс
источник
источник
async/await
не является частью ES7. Прочтите описание тега.Ответы:
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(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
, вероятно, позже, когда они станут родными, изображение будет немного больше.Вы можете увидеть больше объяснений здесь: https://www.promisejs.org/generators/
источник
await
Ключевое слово будет использоваться только вasync function
сек, в то время какyield
ключевое слово должно использоваться только в генераторfunction*
s. И они, очевидно, тоже разные - один возвращает обещания, другой - генераторы.Да,
await
вызоветPromise.resolve
ожидаемую стоимость.yield
просто дает значение вне генератора.источник
Promise.resolve
использует то же самое,new PromiseCapability(%Promise%)
что и спецификация async / await, я просто подумал,Promise.resolve
что лучше понять.Promise.resolve
имеет дополнительное короткое замыкание «IsPromise == true? затем вернуть то же значение», которого нет в async. То есть,await p
wherep
is a промис вернет новое обещание, которое будет разрешено вp
, тогда какPromise.resolve(p)
будет возвращеноp
.Promise.cast
и не рекомендуется по соображениям согласованности. Но это не имеет значения, мы все равно не видим этого обещания.var r = await p; console.log(r);
должен быть преобразован во что-то вроде:,p.then(console.log);
хотяp
может быть создан как:,var p = new Promise(resolve => setTimeout(resolve, 1000, 42));
поэтому неверно говорить « ожидание вызовов Promise.resolve», это какой-то другой код, который находится совсем далеко от выражения 'await', которое вызываетPromise.resolve
, поэтому преобразованноеawait
выражение , то естьPromise.then(console.log)
будет вызван и распечатан42
.tl; dr
Используйте
async
/await
99% времени на генераторах. Почему?async
/await
напрямую заменяет наиболее распространенный рабочий процесс цепочек обещаний, позволяя объявлять код, как если бы он был синхронным, что значительно упрощает его.Генераторы абстрагируются от варианта использования, в котором вы вызываете серию асинхронных операций, которые зависят друг от друга и в конечном итоге будут в состоянии «выполнено». Самый простой пример - это листание результатов, которые в конечном итоге возвращают последний набор, но вы вызываете страницу только по мере необходимости, а не сразу по очереди.
async
/await
на самом деле является абстракцией, построенной на основе генераторов, чтобы упростить работу с обещаниями.См. Очень подробное объяснение Async / Await и генераторов
источник
Попробуйте эти тестовые программы, которые я привык понимать
await
/async
с обещаниями.Программа no1: без обещаний она не запускается последовательно
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');
источник
Во многих отношениях генераторы являются надмножеством async / await. Прямо сейчас async / await имеет более чистую трассировку стека, чем co , самая популярная библиотека на основе async / await-генераторов. Вы можете реализовать свой собственный вариант async / await с помощью генераторов и добавить новые функции, такие как встроенная поддержка для
yield
не обещаний или создание его на наблюдаемых RxJS.Короче говоря, генераторы дают вам большую гибкость, а библиотеки на основе генераторов обычно имеют больше функций. Но async / await - это основная часть языка, он стандартизирован и не будет меняться под вашим руководством, и вам не нужна библиотека для его использования. У меня есть сообщение в блоге с более подробной информацией о разнице между async / await и генераторами.
источник