async function
: используется для определения асинхронной функции, которая возвращает объект AsyncFunction. Асинхронная функция — это функция, которая выполняется асинхронно через цикл обработки событий и возвращает результат через неявное обещание. Если вы используете асинхронные функции в своем коде, вы обнаружите, что их синтаксис и структура будут больше похожи на стандартные синхронные функции.
- Вы также можете использовать выражения асинхронных функций для определения асинхронных функций.
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('calling');
var result = await resolveAfter2Seconds();
console.log(result);
// expected output: 'resolved'
}
asyncCall();
Синтаксис асинхронной функции:
async function name([param[, param[, ... param]]]) { statements }
параметр
- имя имя функции.
- параметр Аргументы для передачи в функцию.
- заявления Оператор тела функции.
возвращаемое значение
Возвращенный объект Promise либо разрешает возвращаемый результат асинхронной функции, либо отклоняет, если асинхронная функция выдает исключение.
описывать
异步函数可以包含await指令,该指令会暂停异步函数的执行,并等待Promise执行, 然后继续执行异步函数,并返回结果。
- Помните, что ключевое слово await допустимо только внутри асинхронных функций. Если вы используете его вне асинхронной функции, будет выдана синтаксическая ошибка.
Обратите внимание, что когда приостановлена асинхронная функция, функция, которую она вызывает, продолжает выполнять (получает неявное обещание, возвращенное Async Function)
- Целью async/await является упрощение поведения синхронизации при использовании множества промисов и выполнении определенных операций с набором промисов. Подобно структуре промисов обратного вызова, async/await больше похож на комбинацию генераторов и промисов.
Пример
var resolveAfter2Seconds = function() {
console.log("starting slow promise");
return new Promise(resolve => {
setTimeout(function() {
resolve("slow");
console.log("slow promise is done");
}, 2000);
});
};
var resolveAfter1Second = function() {
console.log("starting fast promise");
return new Promise(resolve => {
setTimeout(function() {
resolve("fast");
console.log("fast promise is done");
}, 1000);
});
};
var sequentialStart = async function() {
console.log('==SEQUENTIAL START==');
// 1. Execution gets here almost instantly
const slow = await resolveAfter2Seconds();
console.log(slow); // 2. this runs 2 seconds after 1.
const fast = await resolveAfter1Second();
console.log(fast); // 3. this runs 3 seconds after 1.
}
var concurrentStart = async function() {
console.log('==CONCURRENT START with await==');
const slow = resolveAfter2Seconds(); // starts timer immediately
const fast = resolveAfter1Second(); // starts timer immediately
// 1. Execution gets here almost instantly
console.log(await slow); // 2. this runs 2 seconds after 1.
console.log(await fast); // 3. this runs 2 seconds after 1., immediately after 2., since fast is already resolved
}
var concurrentPromise = function() {
console.log('==CONCURRENT START with Promise.all==');
return Promise.all([resolveAfter2Seconds(), resolveAfter1Second()]).then((messages) => {
console.log(messages[0]); // slow
console.log(messages[1]); // fast
});
}
var parallel = async function() {
console.log('==PARALLEL with await Promise.all==');
// Start 2 "jobs" in parallel and wait for both of them to complete
await Promise.all([
(async()=>console.log(await resolveAfter2Seconds()))(),
(async()=>console.log(await resolveAfter1Second()))()
]);
}
// This function does not handle errors. See warning below!
var parallelPromise = function() {
console.log('==PARALLEL with Promise.then==');
resolveAfter2Seconds().then((message)=>console.log(message));
resolveAfter1Second().then((message)=>console.log(message));
}
sequentialStart(); // after 2 seconds, logs "slow", then after 1 more second, "fast"
// wait above to finish
setTimeout(concurrentStart, 4000); // after 2 seconds, logs "slow" and then "fast"
// wait again
setTimeout(concurrentPromise, 7000); // same as concurrentStart
// wait again
setTimeout(parallel, 10000); // truly parallel: after 1 second, logs "fast", then after 1 more second, "slow"
// wait again
setTimeout(parallelPromise, 13000); // same as parallel
ожидание и параллелизм
-
В sequenceStart программа приостанавливается на 2 секунды в первом ожидании, а затем на 1 секунду во втором ожидании. Второй таймер не создается до тех пор, пока не истечет срок действия первого таймера. Программа выполняется за 3 секунды.
-
В concurrentStart одновременно создаются два таймера, а затем выполняется await. Оба таймера запускаются одновременно, что означает, что для завершения работы программы требуется всего 2 секунды, а не 3 секунды, которые являются временем самого медленного таймера.
-
Но ожидание по-прежнему выполняется последовательно, и второе ожидание все равно должно дождаться завершения первого. В этом примере это приводит к тому, что вывод, который завершается первым, появляется после самого медленного вывода.
-
Если вы хотите выполнять две или более задач параллельно, вы должны использовать await Promise.all([job1(), job2()]) как в параллельном режиме.
async/await vs Promise#then и обработка ошибок
-
Большинство асинхронных функций также можно написать с использованием промисов. Однако с точки зрения обработки ошибок асинхронные функции легче перехватывать ошибки исключения.
-
И функция concurrentStart, и функция concurrentPromise в приведенном выше примере функционально эквивалентны. В функции concurrentStart, если какой-либо ожидаемый вызов терпит неудачу, она автоматически перехватывает исключение, выполнение асинхронной функции прерывается, и ошибка передается вызывающей стороне путем неявного возврата обещания.
-
Это также происходит в примере с промисом, где функция должна отвечать за возврат промиса, фиксирующего завершение функции. В функции concurrentPromise это означает, что она возвращает обещание из Promise.all([]).then(). Фактически, предыдущие версии этого примера забыли сделать это!
-
Однако асинхронная функция по-прежнему может игнорировать ошибки по ошибке.
-
Возьмем в качестве примера параллельную асинхронную функцию. Если он не ожидает (или не возвращает) результат вызова Promise.all([]), никакие ошибки распространяться не будут. Хотя пример функции parallelPromise выглядит просто, он вообще не обрабатывает ошибки! Для этого требуется обработчик, аналогичный return Promise.all([]).
Перепишите цепочку обещаний с помощью асинхронной функции
- API, который возвращает обещание, создаст цепочку обещаний, которая разбивает функцию на части. Например следующий код:
function getProcessedData(url) {
return downloadData(url) // 返回一个 promise 对象
.catch(e => {
return downloadFallbackData(url) // 返回一个 promise 对象
})
.then(v => {
return processDataInWorker(v); // 返回一个 promise 对象
});
}
- Можно переписать как одну асинхронную функцию:
async function getProcessedData(url) {
let v;
try {
v = await downloadData(url);
} catch (e) {
v = await downloadFallbackData(url);
}
return processDataInWorker(v);
}
Обратите внимание, что в приведенном выше примере в операторе return нет оператора await, потому что возвращаемое значение асинхронной функции будет неявно передано в Promise.resolve.
Сравнение return await promiseValue и return promiseValue;
Возвращаемое значение неявно передается в Promise.resolve, что не означает, что return await promiseValue и return promiseValue функционально одинаковы.
- Взгляните на приведенный выше код, переписанный ниже, который возвращает null, когда processDataInWorker выдает исключение:
async function getProcessedData(url) {
let v;
try {
v = await downloadData(url);
} catch(e) {
v = await downloadFallbackData(url);
}
try {
return await processDataInWorker(v); // 注意 `return await` 和单独 `return` 的比较
} catch (e) {
return null;
}
}
Простое написание return processDataInworker(v); приведет к тому, что функция вернет обещание, а не null, когда processDataInWorker(v) завершится ошибкой. Есть некоторые тонкие различия между return foo; и return await foo;: return foo; вернет foo напрямую, независимо от того, является ли foo обещанием или отказом. И наоборот, если foo является промисом, return await foo; будет ждать, пока foo разрешится или отклонится, и в случае отклонения вызовет исключение перед возвратом.
Справочная документация:developer.Mozilla.org/this-cn/docs/…
Автор сенсационных заголовков? ? ? ? ?
Добро пожаловать, чтобы внести свой вклад, добро пожаловать, чтобы пожаловаться, спасибо за вашу поддержку ღ( ´・ᴗ・` )