Эта статья предназначена только для технической проверки, записи, общения и ни на кого не направлена. Прости за любую обиду.
Эта статья была впервые опубликована по адресу https://vsnail.cn/static/doc/blog/asyncForEach.html.
Я наткнулся на статью, в которой упоминалосьawait
существуетforEach
не вступает в силу вasync
,await
этоES6
Грамматика в , не должна быть мне незнакомой.Я использовал ее год или два назад.Я знаю, для чего она используется и как ее использовать. Прочитав эту статью, «Седьмое чувство» чувствует, что само название кажется неуместным, а содержание вроде бы в порядке, но после просмотра резюме и остальных комментариев я всегда чувствую, что здесь должно быть недоразумение. . Так что я хочу взглянуть на "его пальто", чтобы узнать, что это за марка (хе-хе-хе... просто посмотрите на марку). После прочтения нескольких подробных вводныхasync
,await
Позже я понял, что решение написать эту статью было ошибкой. Поскольку это слишком глубоко и включает в себя слишком много, это похоже на паровую булочку в «Обещании», которая может вытянуть кучу историй; это также как сильная женская роль с предысторией, и повсюду есть драмы.
Вы можете получить все в этом мире, пока вы достаточно плохи, а вы недостаточно плохи -- "Обещание"
Ну, без лишних слов, давайте к делу. Давайте возьмем часть за частью вместе и посмотрим, что это такое?
async
а такжеawait
ES2017
введен стандартasync
функционировать так, чтобыАсинхронные операции становятся удобнее. Хорошо, посмотрим, как это работает.
async function getBookInfo(name){
const baseInfo = await requestBookBaseInfo(name); //requestBookBaseInfo 方法发送一个请求,向后台请求数据。这是一个异步方法
const bookPrice = await requestBookPrice(baseInfo.id); //requestBookPrice方法发送一个请求,向后台请求数据。这是一个异步方法
return {..baseInfo,bookPrice};
}
getBookInfo
метод, есть две асинхронные функции, и вторая асинхронная функция использует результат первой асинхронной функции. еслиgetBookInfo
Можешь достичь нашей цели, тогда подумай мизинцем и будет прямой вывод.
Оказывается, после использования await внутри асинхронной функции асинхронную функцию, следующую за await, можно сделать синхронной.
Предполагая, что этот вывод верен, как реализована асинхронная функция, дающая такой волшебный эффект?async
Функция возвращает внутреннюю часть функцииreturn
стоимость?await
Только с асинхронными функциями?
Хорошо, с этими вопросами давайте продолжим копать, чтобы увидеть, что это A, B или C, D, E, F, G. . .
Руан Дашен в "Введение в ECMAScript 6"async
Функциональный артикль, упоминающий такое предложение»Что такое асинхронная функция? Одним словом, это синтаксический сахар для Генераторных функций."
Какой?async
даGenerator
синтаксический сахар? Хорошо, тогда давайте возьмем сегодняшнюю женщину № 2,Generator
.
Generator
Функции-генераторы — это решение для асинхронного программирования, предоставляемое ES6, и их синтаксическое поведение полностью отличается от традиционных функций. --- Это также то, что сказал Руан Дашен.
По моему личному пониманию,Generator
Английский дословный перевод «генерировать», затемGenerator
Функция на самом деле является генератором, то, что генерируется, является итератором. Подождите еще один итератор, что это? Ну, оставим ее пока в стороне, все-таки она третья самка, поэтому не так быстро влезла. Если мы не знаем женский номер три, то мы также можемGenerator
понимается какгосударственный менеджер. Ведь великий поэт когда-то сказал: «Глядя на хребет и образуя вершину сбоку», мы просто смотрим на самку №2 под другим углом.
Поставить в известность,Generator
Это обычная функция, но у нее есть еще две очевидные особенности. один в ключевом словеfunction
между именем функции и*
; Во-вторых, используйте внутри функцииyield
Выражения, определяющие различные состояния (обратите внимание, поэтому это также называется источником машины управления состояниями).
function* childEatProcess() {
yield 'use toilet';
yield 'wash hands';
yield 'sit down';
return 'eat'
}
var ch = childEatProcess();
ch.next();//{value:'use toilet',done:false}
ch.next();//{value:'wash hands',done:false}
ch.next();//{value:'sit down',done:false}
ch.next();//{value:'eat',done:true}
ch.next();//{value:'undefined',done:true}
Приведенный выше код определяетGenerator
функции, он имеет три внутриyield
, то есть функция имеет четыре состояния (use toilet
,wash hands
,sit down
так же какreturn
изeat
).childEatProcess
Как и другие функции, ее можно вызывать напрямую. А вот его возвращения (тут обязательно обратите внимание) нет.return
ценность, ноОбъект, объект-указатель на внутреннее состояние, то есть объект Iterator.
а такжеGenerator
Функция аналогична подготовительной работе наших детей перед едой, если его не спровоцировать, то он сам ее не выполнит. когдаch
передачаnext
После метода функция начинает выполняться внутри функции, и она выполняется до тех пор, покаyield
После ключевого слова запуститеyield
следующее выражение, а затем останавливается. Жду, когда ты снова его вызовешь (next
вызов метода)
выражение доходности
из-заGenerator
Объект итератора, возвращаемый функцией, только вызовnext
Метод будет проходить через следующее внутреннее состояние, поэтому он фактически предоставляет функцию, которая может приостановить выполнение.yield
Выражение является флагом паузы.
объект итератораnext
Логика работы метода следующая.
(1) встречаyield
выражение, приостанавливает выполнение следующих операций и сразу последует заyield
Значение следующего выражения в качестве возвращаемого значения объектаvalue
стоимость имущества.
(2) Следующий звонокnext
метод, продолжайте выполнять до следующегоyield
выражение.
(3) Если новых не обнаруженоyield
выражение, оно выполняется до конца функции, покаreturn
заявление, иreturn
Значение выражения, следующего за оператором, в качестве возвращаемого объектаvalue
стоимость имущества.
(4) Если функция не имеетreturn
оператор, возвращаемый объектvalue
Стоимость свойстваundefined
.
должны знать о том,yield
выражение следует за выражением, только если вызываетсяnext
Метод с внутренним указателем будет выполняться только тогда, когда внутренний указатель указывает на оператор, поэтому он равенJavaScript
Обеспечивает ручную "ленивую оценку" (Lazy Evaluation
) грамматические функции.
выражения yield*
и обычныйyield
По сравнению с выражениемyield*
Выражение имеет дополнительную звездочку.yield*
выражение для преобразования следующегоGenerator
выражениевоплощать в жизнь. Это действительно сложно выразить, давайте взглянем на следующий код и почувствуем его интуитивно.
function* generator_1(){
yield "b";
yield "c";
}
function* generator_2(){
yield "a";
yield generator_1();
yield "d";
}
function* generator_3(){
yield "a";
yield* generator_1();
yield "d";
}
let g2 = generator_2();
g2.next();//{value:"a",done:false}
g2.next();//{value:Iterator,done:false}
g2.next();//{value:"d",done:true}
g2.next();//{value:undefined,done:true}
let g3 = generator_3();
g3.next();//{value:"a",done:false}
g3.next();//{value:"b",done:false}
g3.next();//{value:"c",done:false}
g3.next();//{value:"d",done:false}
Из вышеприведенного списка видно, чтоyield
только что казненныйgenerator
функцию, то есть получитьgenerator
Функция сгенерированаiterator
Вот и все. а такжеyield*
, действительно казненныйgenerator
Внутренний указатель функции.
Тогда вы также можете кодировать
function* generator_1(){
yield "b";
yield "c";
}
function* generator_3(){
yield "a";
yield* generator_1();
yield "d";
}
//上面的代码等价于
function* generator_4(){
yield "a";
yield "b";
yield "c";
yield "d";
}
следующий параметр
yield
Само выражение не имеет возвращаемого значения или всегда возвращает неопределенное значение. Следующий метод может принимать один параметр, который будет использоваться как возвращаемое значение предыдущего выражения yield.. Обратите внимание, что это предложение очень важно и является основой для понимания спины. Скажи важные вещи три раза,yield
Само выражение не имеет возвращаемого значения,yield
Само выражение не имеет возвращаемого значения,yield
Само выражение не имеет возвращаемого значения.
Iterator
Как женщина номер три в этой статье,Iterator
, давайте просто забрать его. Ведь она не мастер этой статьи. Но не стоит недооценивать ее, это определенно тяжеловесная героиня, обход объектов, обход массивов, обход псевдомассивов, деструктурирующее присваивание, оператор расширения, все, что можно пройти, неотделимо от ее гранатовой юбки. Только сегодня чуть меньше.
Iterator
Это обходчик, представляющий собой интерфейс, обеспечивающий унифицированный механизм доступа к различным структурам данных. Любая структура данных может быть развернутаIterator
интерфейс, операция обхода может быть завершена (то есть все члены структуры данных обрабатываются по очереди).
Iterator
Процесс обхода такой.
(1) Создайте объект-указатель, указывающий на начальную позицию текущей структуры данных. Другими словами, объект обхода по существу является объектом указателя.
(2) Первый вызов объекта указателяnext
метод, вы можете указать указатель на первый член структуры данных.
(3) Второй вызов объекта указателяnext
метод указатель указывает на второй член структуры данных.
(4) Постоянный вызов объекта указателяnext
метод, пока он не укажет на конец структуры данных.
каждый звонокnext
все методы возвращают информацию о текущем члене структуры данных. В частности, он возвращаетvalue
а такжеdone
Объект с двумя свойствами. в,value
свойство является значением текущего члена,done
Свойство является логическим значением, указывающим, завершен ли обход.
Затем возьмите генератор
Я видел самку номер три(Iterator
) резюме. должно быть ясноGenerator
Объект, возвращаемый после выполнения функции, является объектом обхода внутреннего указателя, а именноIterator
объект.Iterator
Отзыв объектаnext
Метод, обходGenerator
все вyield
определенное состояние.
Я описал женщину номер один раньше и сказал:async
даgenerator
синтаксический сахар, но до сих пор его не вижуgenerator
а такжеasync
Ага отношения. Не волнуйтесь, мы потихоньку приходим. Если первый поворот,async — синтаксический сахар для генераторовЭто предложение верно, то мы, безусловно, можем использоватьgenerator
функция для записиasync
Эффект.
Будуasync
После разборки можно обнаружить, что точек на самом деле две:
- Внутренняя асинхронная функция находится в
async
становится синхронным, т.е.await
После выполнения асинхронного выражения оно будет продолжать выполняться вниз. - для
generator
Сказать,async
выполняется автоматически иgenerator
то, что возвращаетсяiterator
, должен быть вызванnext
, выполнить.
Хорошо, тогда мы будем реализовывать эти два пункта один за другим:
Первый пункт на самом деле очень прост, затем используйте функцию обратного вызова,promise
И так далее можно добиться последовательного выполнения.
Беда в том, чтобы позволитьGenerator
Функция запускается автоматически вместо того, чтобы мы вызывали ее вручнуюnext
.
Автоматически запускать генератор
Thunk
функция выполняется автоматическиGenerator
Метод функции.
Давным-давно возник спор о «стратегии оценки», когда должны оцениваться аргументы функции. Некоторые люди думают, что выражения должны оцениваться при их использовании, чтобы избежать ненужных вычислений, что эквивалентноназывать по имени. Некоторые считают, что выражение следует вычислять перед использованием, что эквивалентновызов по значению.
а такжеThunk
Это реализация вызова по имени, которая заключается в том, чтобы поместить параметры во временную функцию, а затем передать временную функцию в тело функции.
Язык JavaScript вызывается по значению, егоThunk
Функции имеют разные значения. существуетJavaScript
язык,Thunk
Вместо выражения функция заменяет функцию с несколькими аргументами, заменяя ее функцией с одним аргументом, которая принимает только функцию обратного вызова в качестве аргумента. Кажется, это концепция с функцией курирования.
function readSome(a,b,callBack){
setTimeout(function(){
callBack && callBack(a+b);
},200)
}
let thunkFun = function(fn){
return function(...args){
return function(callBack){
return fn.call(this,...args,callBack);
}
}
}
let thunk_rs = thunkFun(readSome);
thubk_rs('Hi','girl')(function(str){
console.log(str);
})
Вы можете спросить,Thunk
函数有什么用? а такжеGenerator
При чем здесь самоисполнение. . Не торопитесь, одежду собирают по частям и носят по частям.
function* gen() {
// ...
}
var g = gen();
var res = g.next();
while(!res.done){
console.log(res.value);
res = g.next();
}
В приведенном выше кодеGenerator
функцияgen
Все шаги выполняются автоматически.
Однако это не подходит для асинхронных операций. Если необходимо обеспечить выполнение предыдущего шага до того, как можно будет выполнить следующий шаг, указанное выше автоматическое выполнение невозможно. В настоящее время,Thunk
Функции могут пригодиться.
function readSome(a,b,callBack){
setTimeout(function(){
callBack && callBack(a+b);
},200)
}
let thunkFun = function(fn){
return function(...args){
return function(callBack){
return fn.call(this,...args,callBack);
}
}
}
let thunk_rs = thunkFun(readSome);
var gen = function* (){
var r1 = yield thunk_rs('Hi','girl');
console.log(r1.toString());
var r2 = yield readFileThunk('you are ','beautiful');
console.log(r2.toString());
};
function run(fn){
var gen = fn();
function next(err,data){
let rs = gen.next(data);
if(rs.done) return ;
rs.value(next)
}
next();
}
run(gen)
Кажется, что это идеально завершает автоматическое выполнение. Конечно, автоматическое выполнение происходит не только таким образом.
асинхронный принцип
Из нашего предыдущего понимания мы знаем, чтоasync
Принцип на самом делеGenerator
Функция и самоисполнитель заключены в функцию. Так что толькоasync
даGenerator
синтаксический сахарный аргумент. Правда раскрывается, оказывается, что женщина № 1 - это женщина № 2 в жилете, но этот жилет дает женщине № 1 некоторые особые способности. Точно так же, как Супермен должен носить свою боевую форму, чтобы называться Суперменом и обладать сверхспособностями.
Затем выберите асинхронность
Ношение жилетки естественно местами разное, хотя внутренние данные одинаковые. Итак, давайте посмотрим на разницу после того, как наденете жилет.
async
ФункцияGenerator
Улучшение функции отражено в следующих четырех пунктах.
(1) Встроенный привод. Это то, что мы называем самоисполнением.
(2) Лучшая семантика.
(3) Более широкая применимость.
(4)обещание возвращаемого значения
Наиболее важными являются первый и четвертый пункты. Пункт первый, его все на земле знают, не будем об этом.Четвертый пункт, вернуть объект обещания,а такжеgenerator
вернутьiterator
объект. Это очень важное отличие.
Фактическиasync
Когда функция выполняется, как только она встречаетawait
вернется первым (вернутьpromise
объект), дождитесь завершения асинхронной операции, а затем выполните операторы, следующие за телом функции.async
внутри функцииreturn
Значение, возвращаемое оператором, станетthen
Параметры функции обратного вызова метода.
Разобрать эту булочку
Кровавое дело было возбуждено из-за паровой булочки, а сегодняшняя акция по сбору одежды была вызвана статьей. Тогда давайте вернемся и посмотрим на эту статью «Почему ожидание не работает в forEach».
В статье есть такой кусок кода:
function test() {
let arr = [3, 2, 1]
arr.forEach(async item => {
const res = await fetch(item)
console.log(res)
})
console.log('end')
}
function fetch(x) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x)
}, 500 * x)
})
}
test()
Прочитав статью, я, наверное, понял, что этот код на самом деле хочет сделать одну вещь, хотя он и асинхронный, но я хочу отображать элементы в массиве в порядке сортировки массива. При использовании обхода forEach это требование не выполняется. Отсюда и название статьи. Но женщина номер один сказала, что этот горшок я не ношу. Дело не в том, что я не могу, а в том, что вы не вписали меня в хороший сценарий.
Давай, давайте изменим сценарий, все еще вforEach
Внутри, но повозитесь с функцией обратного вызова внутри.
function test() {
let arr = ["a", "b", "c"]
arr.forEach(async (item,index) => {
console.log('循环第'+index+'次')
const res = await fetch(item)
console.log('res',res)
const res1 = await fetch1(res);
console.log('res1',res1)
})
console.log('end')
}
function fetch(x,index) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x+"经过fetch处理")
}, 500)
})
}
function fetch1(x) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x+" 经过fetch1处理")
}, 100)
})
}
test()
этот скрипт,async
В функции задаются два асинхронных выраженияawait
. и оба последниеawait
Асинхронное выражение использует предыдущийawait
Возвращаемое значение асинхронного выражения используется в качестве параметра. То есть, еслиasync
существуетforEach
Если есть функция, то последнее асинхронное выражение обязательно будет использовать в качестве параметра возвращаемое значение первого асинхронного выражения. То есть ожидаемый выходной эффект должен быть:
цикл 0
цикл 1
2-й цикл
end
undefined
res a обрабатывается выборкой
res b обрабатывается выборкой
res c обрабатывается выборкой
res1 a обрабатывается fetch и обрабатывается fetch1
res1 b обрабатывается fetch и обрабатывается fetch1
res1 c обрабатывается fetch и обрабатывается fetch1
Уважаемые, можете попробовать, это выход такой. Эй, я пробовал, и это действительно так.
Давайте посмотрим, почему сценарий один не достигает своей цели, а сценарий два достигает своей цели? очень простой,async
Что возвращает функция, что возвращаетсяpromise
, является асинхронным объектом. а такжеforEach
является функцией обратного вызова одна за другой, что означает, что эти функции обратного вызова будутвыполнить немедленно, при выполнении наawait
Когда ключевое слово рядом, он вернетpromise
объект,async
Внутри функция заморожена, ожидаяawait
После выполнения следующего асинхронного выражения выполните его снова.async
Оставшийся код внутри функции. Итак, скрипт one forEach получает кучуpromise
объект вместоasync
Результат выполнения внутри функции.async
функциональные гарантии являются внутренними для функцииawait
последовательность выполнения. Тогда это можно объяснитьasync
существуетforEach
Это работает, но сцена не подходит.
Суммировать
На самом деле, неважноasync
ещеgenerator
Есть еще много моментов, которые не набраны.async
а такжеgenerator
Появление асинхронной обработки функций — действительно качественный скачок по сравнению с исходной пирамидой функций обратного вызова,promise
С точки зрения несемантики,async
Вполне способна сыграть главную женскую роль.
использованная литература
1. «Повторное изучение JS: почему ожидание не действует в forEach»juejin.cn/post/1
2. «Введение в ECMAScript 6»es6.ruanyifeng.com/#docs/async