Понимание асинхронности/ожидания

JavaScript

предисловие

js имеет множество решений для асинхронной обработки, в то время какasync/awaitЭто один из них.В последнее время я изучаю и использую koa.На стороне сервера обещания используются редко, но выбираются более элегантные.async/await. Конечно, когда появляется новое решение, нужно не только научиться писать, но и изучить его принципы.

Что делает async/await?

async/awaitБуквально хорошо понял,asyncзначит асинхронный.awaitОно имеет значение ожидания, и то же самое верно в использовании обоих.asyncобъявитьfunctionявляется асинхронным, в то время какawaitИспользуется для ожидания завершения выполнения асинхронного метода.

async

Синтаксис async очень прост, достаточно добавить ключевое слово в начало функции, например:

async function f() {
    return 1;
}

Значение ключевого слова async очень простое, то есть функция возвращает обещание.

async function f() {
    return 1;
}
f().then((res) => {
    console.log(res)
}) // 1

Асинхронная функция вернет объект обещания. Если функция возвращает значение, асинхронная будет напрямую использоватьPromise.resolve()Упакуйте обратно.

await

Ключевые слова ждать ждать означало, чего же тогда он ждет? MDN написано на:

[return_value] = await expression;

Ожидается выражение, тогда выражение может быть константой, переменной, промисом, функцией и т. д.

function getSomething() {
    return "something";
}

async function testAsync() {
    return Promise.resolve("hello async");
}

async function test() {
    const v1 = await getSomething();
    const v2 = await testAsync();
    console.log(v1, v2);
}

test(); // something hello async
  • Почему ключевое слово await можно использовать только в асинхронных функциях

Оператор await ожидает возвращаемого результата, поэтому, если он синхронный, он возвращается напрямую.

Если он асинхронный, то в случае асинхронного await заблокирует весь процесс, и следующий код не будет продолжаться до тех пор, пока не будет возвращен результат.

Блокирующий код — ужасная вещь, а асинхронные функции будут завернуты в промис и выполняться асинхронно. Следовательно, await можно использовать только в асинхронных функциях, если его использовать в обычной программе, это приведет к блокировке всей программы, что не стоит потерь.

Обработка ошибок в async/await

Обещание — это не только один из видов решимости, но и один из видов отказа. А await только ждет результата, так что мне делать, если возникает ошибка?

  • Ошибка перехвата с помощью try-catch
async function myFunction() {
  try {
    await Promise.reject('1');
  } catch (err) {
    console.log(err);
  }
}
myFunction(); // 1
  • Используйте улов обещания, чтобы поймать ошибку
async function myFunction() {
    await Promise.reject('1').catch((err) => {
        console.log(err);
    });
}
myFunction(); // 1

Разница между async/await и обещанием

Самая большая проблема с промисами в том, что после усложнения бизнеса внутренняя логика потом тоже усложняется, либо не так красиво будут написаны асинхронные сценарии вложенности циклов и т.д.

Я произвольно привожу вложенный пример, а затем используюasync/awaitа такжеpromise, вы можете почувствовать разницу между ними:

function takeLongTime(n) {
    return new Promise(resolve => {
        setTimeout(() => resolve(n), n);
    });
}
function step1(n) {
    console.log(`step1 with ${n}`);
    return takeLongTime(n);
}

function step2(m, n) {
    console.log(`step2 with ${m} and ${n}`);
    return takeLongTime(m + n);
}

function step3(k, m, n) {
    console.log(`step3 with ${k}, ${m} and ${n}`);
    return takeLongTime(k + m + n);
}

Функция takeLongTime заключается в предоставлении задержанных данных после задержки.

step1 представляет, как долго первый шаг задерживается.

step2 представляет общую задержку первого и второго шагов.

step3 показывает, как долго были задержаны первый, второй и третий шаги.

  • обещанная версия
function doIt() {
    console.time("doIt");
    const time1 = 300;
    step1(time1)
        .then(time2 => {
            return step2(time1, time2)
                .then(time3 => [time1, time2, time3]);
        })
        .then(times => {
            const [time1, time2, time3] = times;
            return step3(time1, time2, time3);
        })
        .then(result => {
            console.log(`result is ${result}`);
            console.timeEnd("doIt");
        });
}

doIt();
  • асинхронная/ждущая версия
async function doIt() {
    console.time("doIt");
    const time1 = 300;
    const time2 = await step1(time1);
    const time3 = await step2(time1, time2);
    const result = await step3(time1, time2, time3);
    console.log(`result is ${result}`);
    console.timeEnd("doIt");
}

doIt();

В этой сложной логике мы можем найтиasync/awaitУ него есть преимущества перед цепями.

Суммировать

Async/await — асинхронное решение, и koa поддерживает эту возможность, поэтому при написании серверного кода на основе koa этот синтаксический сахар неизбежен, его изучение и использование — наш обязательный курс.