асинхронно/ожидание, понятно?

Node.js база данных ECMAScript 6

Так как писать статью было уже поздно, я был немного сонным и скопировал неправильный код, который был исправлен.

В предыдущем блоге мы объяснили промисы с точки зрения практического использования и интервью (исходный текст см. в разделе "Разговор об обещаниях для вопросов интервью и практического использования"), но метод Promise решает ад обратного вызова, но этот метод полон промисовскихthen()Метод, если процесс сложный, код будет заполнен целикомthen, поток кода не может очень хорошо представлять поток выполнения.

Почему асинхронный/ожидающий

В es6 мы можем использовать функцию Generator для управления потоком, как показано в следующем коде:

function* foo(x) {
    yield x + 1;
    yield x + 2;
    return x + 3;
}

Мы можем непрерывно вызывать объект Generator в соответствии сnext()способ управления потоком функции. Но это не кажется таким смысловым. Поэтому синтаксическая сахарная асинхронная функция функции Generator инкапсулирована в ES6, но определена в es7. Определено ES7asyncФункции, наконец, дают JavaScript идеальное решение для асинхронных операций.AsyncФункции — это синтаксический сахар для функций-генераторов. использовать ключевые словаAsyncЧтобы указать это, используйте await внутри функции для обозначения асинхронности. По сравнению с генератором улучшение асинхронной функции заключается в следующих моментах: выполнение функции генератора должно зависеть от исполнителя, аAsync()У функции есть свой исполнитель, а метод вызова такой же, как и у обычных функций.Asyncи ждать по сравнению с*а такжеyieldболее семантический.asyncВозвращаемое значение функции — это объект Promise, который более удобен, чем объект Iterator, возвращаемый функцией Generator, и может использоваться напрямую.then()способ вызова.

Затем давайте проиллюстрируем использование функции async/await с помощью небольшого фрагмента кода:

Функции синхронизации без async/await:

fn = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(1)
    }, 2000)
  })
}
const Fn = () =>{
  fn().then((res) => {
    console.log(res)
  })
}
Fn()
console.log(2)

Я считаю, что все программисты, которые могут видеть здесь, должны знать выходной статус этого кода: сначала напечатать 2, а затем напечатать 1 через 2 с.

Функции синхронизации с использованием async/await:

fn = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(1)
    }, 2000)
  })
}
const Fn = async () => {
  await fn().then((res) => {
    console.log(res)
  })
  console.log(2)
}
Fn()

Вывод этой функции: 1 печатается через 2 с, а затем печатается 2.

Тогда почему?

Мы понимаем два слова асинхронный и ожидающий буквально: асинхронный означает асинхронный, асинхронный используется для определения асинхронной функции, которая возвращает промис. ; await означает ждать, Promise — это обещание, await — это тоже обещание. Обещание Promise состоит в том, чтобы выводить возвращаемое значение в функцию возврата then, независимо от того, успешно это происходит или нет. Обещание ожидания заключается в том, что независимо от того, ветрено или дождливо, я буду ждать, пока вы закончите выполнять другие шаги. Поэтому в приведенном выше коде, который использует async/await, он будет ждать, пока fn полностью запустится, а асинхронный обратный вызов завершит обработку возвращаемого значения, прежде чем начинать следующую операцию. Идея состоит в том, чтобы превратить асинхронную функцию в синхронную операцию.

практическое использование

В работе на прошлой неделе я много раз использовал async/await в работе сканера, основанной на узле, для управления потоком выполнения программы:

//伪代码
let axiosArr = [];
for (let i = 0, len = arr.length; i < len; i++) {
  let params = qs.stringify({
    'param': arr[i].index,
  })
  axiosArr.push(axios.post(url, params, {
    headers
  }))
}
/*
*上面的循环是循环抓取2345条数据,平均每个数据要访问16个接口
*用axios.all同时询问,当返回结束后将返回值处理
*然后将返回值存储到mongodb数据库中
*/
await axios.all(axiosArr).then(
  axios.spread(function () {
    for (let i = 0, len = arguments.length; i < len; i++) {
      let str = `${unescape(arguments[i].data.replace(/\\u/g, '%u'))}`;
      str = basics.subStr(basics.deletN(basics.deletS(basics.cutStr(str))));
      concentArr[i].concent = str
    }
    mg.mongodbMain({
      name: obj.name,
      alias: obj.alias,
      type: type,
      url: obj.url,
      drugsConcent: concentArr
    })
  }))

На самом деле операция настолько проста, что все поймут, посмотрев на код. Но проблема в том, что когда я не использую async/await, он сначала получит доступ к 2000+ данным и будет постоянно обращаться к своим 16 интерфейсам, но поскольку функция обратного вызова promise является асинхронной, она будет зависать, и вместо прямого хранения данных в базу данных. Кажется, это отличается от того, что мы ожидали. Поэтому здесь я использую функцию async/await, использую синхронизацию для обработки асинхронных операций и синхронизирую промисы.Когда axios.all обращается к 16 интерфейсам каждого фрагмента данных, данные напрямую сохраняются в базе данных, а затем происходит переход к следующий уровень цикла, есть еще 16 интерфейсов для доступа к следующему фрагменту данных.

Последствия async/await

мы сказалиasyncВозвращаемое значение функции является объектом Promise.

const delay = timeout => new Promise(resolve=> setTimeout(resolve, timeout));
async function f(){
    await delay(1000);
    await delay(2000);
    await delay(3000);
    return 'done';
}

f().then(v => console.log(v));// 6s之后打印'done'

Как только внутри он выбрасывает исключение, это приведет к тому, что состояние возврата объекта станет Promiserejectусловие. Выданная ошибка будетcatchПолучена функция обратного вызова метода.

async function e(){
    throw new Error('error');
}
e().then(v => console.log(v))
.catch( e => console.log(e));//抛出的错误会被catch捕捉到

Кроме того, у async есть схожая с promise.all фича, то есть во внутренней точке есть функция await для сообщения об ошибке, и последующее выполнение выполняться не будет.

let fn1 = ()=>{
    return new Promise((resolve,reject) => {
        setTimeout(()=>{
            reject('故意抛出错误');
        },500);
    });
}

let fn2 = ()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve(1);
        },500);
    });
}

let getList = async ()=>{
    let a = await fn1();
    let b = await fn2();
    return {first: a,second:b};
}
getList().then(result=> {
    console.log(result);
}).catch(err=> {
    console.log(err);// 由于fn1的报错,async的状态直接变成了rejected
});

Когда появились Promises, казалось, что ад обратных вызовов пришел в упадок. Когда появился Async/Await, асинхронность, наконец, не была сложной вещью.