Это 77-я оригинальная статья без воды.Если вы хотите получить больше оригинальных статей, выполните поиск в общедоступном аккаунте и подпишитесь на нас~ Эта статья была впервые опубликована в блоге Zhengcaiyun:Пишите качественный поддерживаемый код — асинхронная оптимизация
предисловие
В текущей разработке интерфейса частота асинхронных операций становится все выше и выше, особенно для использования запросов интерфейса данных и таймеров, поэтому мы должны обратить внимание на сценарии, с которыми сталкивается асинхронность в бизнесе, и на оптимизацию асинхронности. . Неправильная асинхронная обработка может вызвать множество проблем, таких как отрисовка страницы, повторная загрузка и т.д.
Далее мы кратко начнем с того, какие асинхронные типы в JavaScript являются точками входа, а затем перечислим некоторые сценарии, с которыми мы столкнемся в бизнесе, для последовательного анализа и способы их решения.
Типы асинхронных реализаций
Во-первых, есть примерно следующие способы реализации асинхронности:
callback
callback — это функция обратного вызова. Этот парень появился очень рано, и он на самом деле является основным способом борьбы с асинхронностью. И концепция обратного вызова появляется не только в JavaScript, вы также можете найти ее тень во внутренних языках, таких как Java или C#.
Короче говоря, функция обратного вызова на самом деле является функцией, которая передает параметры другой основной функции. После того, как выполнение хост-функции завершено или выполнено до определенного этапа, функция обратного вызова запускается и выполняется, а затем результат выполнения возвращается в хост-функцию.
Например, второй метод setTimeout или setState в React, с которым мы знакомы, заключается в решении асинхронной реализации в виде функции обратного вызова.
setTimeout(() => {
//等待0.2s之后再做具体的业务操作
this.doSomething();
}, 200);
this.setState({
count: res.count,
}, () => {
//在更新完count之后再做具体的业务操作
this.doSomething();
});
Promise
Promise — хорошая штука, с его помощью мы можем выполнять множество асинхронных операций, и мы можем работать асинхронно в цепочке.
На самом деле deferred в JQuery немного похож на него Оба решения используют функции обратного вызова, которые могут быть объединены в цепочку, но добавление неправильного метода catch в Promise может упростить обработку сценариев исключений, и он имеет встроенный статус (разрешить, reject, pending), состояние может быть изменено только с pending на одно из двух других, и это изменение необратимо и не может быть изменено снова.
let promise = new Promise((resolve, reject) => {
reject("对不起,你不是我的菜");
});
promise.then((data) => {
console.log('第一次success' + data);
return '第一次success' + data
},(error) => {
console.log(error) }
).then((data2) => {
console.log('第二次success' + data2);
},(error2) => {
console.log(error2) }
).catch((e) => {
console.log('抓到错误啦' + e);
});
await/async
await/async на самом деле является обновленной версией Promise.При использовании await/async для вызова асинхронного кода он выполняется последовательно сверху вниз, точно так же, как при написании синхронного кода, который больше соответствует нашим привычкам кодирования и логике мышления.Так просто чтобы понять. Общая логика кода также станет более понятной.
async function asyncDemoFn() {
const data1 = await getData1();
const data2 = await getData2(data1);
const data3 = await getData3(data2);
console.log(data3)
}
await asyncDemoFn()
generator
Генератор по-китайски называется Конструктор. Это новинка в ES6. Я считаю, что многие люди редко касаются его в реальном коде, поэтому он для всех относительно непонятен, но этот парень все еще очень силен. Да, простыми словами, он может управлять асинхронными вызовами и фактически является конечным автоматом.
function* foo() {
for (let i = 1; i <= 3; i++) {
let x = yield `等我一下呗,i = ${i}`;
console.log(x);
}
}
setTimeout(() => {
console.log('终于轮到我了');
}, 1);
var a = foo();
console.log(a); // foo {<closed>}
var b = a.next();
console.log(b); // {value: "等我一下呗,i = 1", done: false}
var c = a.next();
console.log(c); // {value: "等我一下呗,i = 2", done: false}
var d = a.next();
console.log(d); // {value: "等我一下呗,i = 3", done: false}
var e = a.next();
console.log(e); // {value: undefined, done: true}
// 终于轮到我了
Функция foo в приведенном выше коде — это сопрограмма, а ее сила — команда yield. Это означает, что выполнение находится здесь, и право выполнения будет передано другим сопрограммам. То есть команда yield является разделительной линией между двумя фазами асинхронности.
Сопрограмма приостанавливается, когда встречает команду yield, ждет, пока не вернется право на выполнение, а затем возобновляет выполнение с того места, где оно было приостановлено. Его самое большое преимущество в том, что код написан очень похоже на синхронную операцию, если убрать команду yield, то все точно так же.
Давайте использовать генераторы немного ближе к сценарию. Например, теперь на странице нам нужно автоматически выполнять проверки checkAuth и checkAddress, мы используем метод генератора для автоматической проверки двух вышеупомянутых асинхронных проверок.
const checkAuth = () => {
return new Promise((resolve)=>{
setTimeout(()=>{
resolve('checkAuth1')
},1000)
})
}
const checkAddress = () => {
return new Promise((resolve)=>{
setTimeout(()=>{
resolve('checkAddress2')
},2000)
})
}
var steps = [checkAuth,checkAddress]
function* foo(checkList) {
for (let i = 0; i < checkList.length; i++) {
let x = yield checkList[i]();
console.log(x);
}
}
var stepsGen = foo(steps)
var run = async (gen)=>{
var isFinnish = false
do{
const {done,value} = gen.next()
console.log('done:',done)
console.log('value:',value)
const result = await value
console.log('result:',result)
isFinnish = done
}while(!isFinnish)
console.log('isFinnish:',isFinnish)
}
run(stepsGen)
Сравнение типов
- С утра до ночи из измерения времени: обратный вызов, обещание, генератор, ожидание/асинхронность
- await/async в настоящее время является окончательной формой асинхронности.
- Обратный вызов дает нам базовый способ справиться с асинхронными ситуациями Промис прощается с адом обратных вызовов и добавляет разрешение, отклонение и перехват, чтобы мы могли справляться с различными ситуациями Генератор повышает работоспособность асинхронного режима, аналогичного состоянию Машина может временно остановить несколько асинхронные выполнения, а затем продолжить выполнение оставшихся асинхронных вызовов, когда это необходимо. await/async делает асинхронные вызовы более семантическими и автоматически выполняет асинхронное выполнение.
Сценарии, встречающиеся в асинхронном бизнесе
ад обратного звонка
При использовании функции обратного вызова у нас может быть такой сценарий, B должен продолжать вызывать после возврата A, поэтому, когда есть такая связь, возникает проблема, называемая callback hell.
getData1().then((resData1) => {
getData2(resData1).then((resData2) => {
getData3(resData2).then((resData3)=>{
console.log('resData3:', resData3)
})
});
});
В такой ситуации мы можем попробовать использовать await/async для решения проблемы множественной глубокой вложенности.
async function asyncDemoFn2() {
const resData1 = await getData1();
const resData2 = await getData2(resData1);
const resData3 = await getData3(resData2);
console.log(resData3)
}
await asyncDemoFn2()
Асинхронный цикл
В бизнесе мы чаще всего сталкиваемся с проблемой последовательности множественных асинхронных вызовов, которые можно условно разделить на следующие категории:
параллельное выполнение
При параллельном выполнении мы можем напрямую использовать метод all класса Promise.
Promise.all([getData1(),getData2(),getData3()]).then(res={
console.log('res:',res)
})
Последовательное исполнение
При последовательном выполнении мы можем сделать это следующими двумя способами.
- Используйте async/await для
const sources = [getData1,getData2,getData3]
async function promiseQueue() {
console.log('开始');
for (let targetSource in sources) {
await targetSource();
}
console.log('完成');
};
promiseQueue()
- Используйте async/await с while
//getData1,getData2,getData3 都为promise对象
const sources = [getData1,getData2,getData3]
async function promiseQueue() {
let index = 0
console.log('开始');
while(index >=0 && index < sources.length){
await targetSource();
index++
}
console.log('完成');
};
promiseQueue()
- Используйте async/await с уменьшением
//getData1,getData2,getData3 都为promise对象
const sources = [getData1,getData2,getData3]
sources.reduce(async (previousValue, currentValue)=>{
await previousValue
return currentValue()
},Promise.resolve())
- использовать рекурсию
const sources = [getData1,getData2,getData3]
function promiseQueue(list , index = 0) {
const len = list.length
console.log('开始');
if(index >= 0 && index < len){
list[index]().then(()=>{
promiseQueue(list, index+1)
})
}
console.log('完成');
}
promiseQueue(sources)
конец
Сегодня просто обсуждение распространенных сценариев использования асинхронности и несколько простых примеров. На самом деле существует очень много сложных сценариев использования асинхронности. Больше причуд ждут вас.
использованная литература
Шесть схем асинхронного программирования JS
6 причин, по которым Async/Await заменяет обещания
4 метода асинхронного программирования в Javascript
Рекомендуемое чтение
Как построить систему тестирования производительности от 0 до 1
Говоря о моем понимании FaaS с Alibaba Cloud FC
Карьера
ZooTeam, молодая, увлеченная и творческая команда, связанная с отделом исследований и разработок продукции Zhengcaiyun, базируется в живописном Ханчжоу. В настоящее время в команде более 40 фронтенд-партнеров, средний возраст которых составляет 27 лет, и почти 30% из них — инженеры полного стека, настоящая молодежная штурмовая группа. В состав членов входят «ветераны» солдат из Ali и NetEase, а также первокурсники из Чжэцзянского университета, Университета науки и технологий Китая, Университета Хандянь и других школ. В дополнение к ежедневным деловым связям, команда также проводит технические исследования и фактические боевые действия в области системы материалов, инженерной платформы, строительной платформы, производительности, облачных приложений, анализа и визуализации данных, а также продвигает и внедряет ряд внутренних технологий. Откройте для себя новые горизонты передовых технологических систем.
Если вы хотите измениться, вас забрасывают вещами, и вы надеетесь начать их бросать; если вы хотите измениться, вам сказали, что вам нужно больше идей, но вы не можете сломать игру; если вы хотите изменить , у вас есть возможность добиться этого результата, но вы не нужны; если вы хотите изменить то, чего хотите достичь, вам нужна команда для поддержки, но вам некуда вести людей; если вы хотите изменить установившийся ритм, это будет "5 лет рабочего времени и 3 года стажа работы"; если вы хотите изменить исходный Понимание хорошее, но всегда есть размытие того слоя оконной бумаги.. , Если вы верите в силу веры, верьте, что обычные люди могут достичь необыкновенных вещей, и верьте, что они могут встретить лучшего себя. Если вы хотите участвовать в процессе становления бизнеса и лично способствовать росту фронтенд-команды с глубоким пониманием бизнеса, надежной технической системой, технологиями, создающими ценность, и побочным влиянием, я думаю, что мы должны говорить. В любое время, ожидая, пока вы что-нибудь напишете, отправьте это наZooTeam@cai-inc.com