Пишите качественный поддерживаемый код — асинхронная оптимизация

внешний интерфейс
Пишите качественный поддерживаемый код — асинхронная оптимизация

Это 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)
})

Последовательное исполнение

При последовательном выполнении мы можем сделать это следующими двумя способами.

  1. Используйте async/await для
const sources = [getData1,getData2,getData3]
async function promiseQueue() {
  console.log('开始');
  for (let targetSource in sources) {
    await targetSource();
  }
  console.log('完成');
};
promiseQueue()
  1. Используйте 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()
  1. Используйте async/await с уменьшением
//getData1,getData2,getData3 都为promise对象
const sources = [getData1,getData2,getData3]
sources.reduce(async (previousValue, currentValue)=>{
  await previousValue
  return currentValue()
},Promise.resolve())
  1. использовать рекурсию
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