Асинхронные функции , функция в ES2017 , делают асинхронный код синхронизированным с помощью обещаний (особая форма асинхронного кода) и await
ключевого слова. Также обратите внимание на примеры кода ниже ключевого слова async
перед function
ключевым словом, которое обозначает функцию async / await. await
Ключевое слово не будет работать , не будучи в функции предварительного фиксированной с async
ключевым словом. Поскольку в настоящее время нет исключения из этого, это означает, что не будет работать ожидание верхнего уровня (ожидание верхнего уровня означает ожидание вне какой-либо функции). Хотя есть предложение на высшем уровнеawait
.
ES2017 был утвержден (то есть окончательно доработан) как стандарт для JavaScript 27 июня 2017 года. Async await может уже работать в вашем браузере, но если нет, вы все равно можете использовать эту функциональность с помощью транспортера javascript, такого как babel или traceur . Chrome 55 имеет полную поддержку асинхронных функций. Так что если у вас более новый браузер, вы можете попробовать код ниже.
См . Таблицу совместимости с кангаксом es2017 для совместимости с браузером.
Вот пример вызываемой функции асинхронного ожидания, doAsync
которая берет три паузы в одну секунду и печатает разницу во времени после каждой паузы от времени начала:
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
function doSomethingAsync () {
return timeoutPromise(1000);
}
async function doAsync () {
var start = Date.now(), time;
console.log(0);
time = await doSomethingAsync();
console.log(time - start);
time = await doSomethingAsync();
console.log(time - start);
time = await doSomethingAsync();
console.log(time - start);
}
doAsync();
Когда ключевое слово await помещается перед значением обещания (в этом случае значением обещания является значение, возвращаемое функцией doSomethingAsync), ключевое слово await приостанавливает выполнение вызова функции, но не приостанавливает другие функции и продолжает выполнение другого кода до разрешения обещания. После того, как обещание разрешено, оно развернет значение обещания, и вы можете думать, что выражение ожидания и обещания теперь заменяется этим развернутым значением.
Итак, поскольку await просто делает паузу, ждет, а затем разворачивает значение перед выполнением остальной части строки, вы можете использовать его для циклов и внутренних вызовов функций, как в примере ниже, который собирает ожидаемые во времени различия в массиве и распечатывает массив.
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
function doSomethingAsync () {
return timeoutPromise(1000);
}
// this calls each promise returning function one after the other
async function doAsync () {
var response = [];
var start = Date.now();
// each index is a promise returning function
var promiseFuncs= [doSomethingAsync, doSomethingAsync, doSomethingAsync];
for(var i = 0; i < promiseFuncs.length; ++i) {
var promiseFunc = promiseFuncs[i];
response.push(await promiseFunc() - start);
console.log(response);
}
// do something with response which is an array of values that were from resolved promises.
return response
}
doAsync().then(function (response) {
console.log(response)
})
Сама асинхронная функция возвращает обещание, так что вы можете использовать его как обещание с цепочкой, как я делал выше или в другой функции асинхронного ожидания.
Приведенная выше функция будет ожидать каждого ответа перед отправкой другого запроса, если вы хотите отправлять запросы одновременно, вы можете использовать Promise.all .
// no change
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
// no change
function doSomethingAsync () {
return timeoutPromise(1000);
}
// this function calls the async promise returning functions all at around the same time
async function doAsync () {
var start = Date.now();
// we are now using promise all to await all promises to settle
var responses = await Promise.all([doSomethingAsync(), doSomethingAsync(), doSomethingAsync()]);
return responses.map(x=>x-start);
}
// no change
doAsync().then(function (response) {
console.log(response)
})
Если обещание может быть отклонено, вы можете заключить его в попытку catch или пропустить попытку try и позволить ошибке распространиться на вызов catch функций async / await. Вы должны быть осторожны, чтобы не оставлять ошибки в обещаниях необработанными, особенно в Node.js. Ниже приведены некоторые примеры, показывающие, как работают ошибки.
function timeoutReject (time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
reject(new Error("OOPS well you got an error at TIMESTAMP: " + Date.now()));
}, time)
})
}
function doErrorAsync () {
return timeoutReject(1000);
}
var log = (...args)=>console.log(...args);
var logErr = (...args)=>console.error(...args);
async function unpropogatedError () {
// promise is not awaited or returned so it does not propogate the error
doErrorAsync();
return "finished unpropogatedError successfully";
}
unpropogatedError().then(log).catch(logErr)
async function handledError () {
var start = Date.now();
try {
console.log((await doErrorAsync()) - start);
console.log("past error");
} catch (e) {
console.log("in catch we handled the error");
}
return "finished handledError successfully";
}
handledError().then(log).catch(logErr)
// example of how error propogates to chained catch method
async function propogatedError () {
var start = Date.now();
var time = await doErrorAsync() - start;
console.log(time - start);
return "finished propogatedError successfully";
}
// this is what prints propogatedError's error.
propogatedError().then(log).catch(logErr)
Если вы идете сюда то увидите готовые предложения для будущих версий ECMAScript.
Альтернативой этому, которая может использоваться только с ES2015 (ES6), является использование специальной функции, которая оборачивает функцию генератора. Функции генератора имеют ключевое слово yield, которое можно использовать для репликации ключевого слова await с окружающей функцией. Ключевое слово yield и функция генератора имеют гораздо более общее назначение и могут выполнять гораздо больше функций, чем просто функция асинхронного ожидания. Если вы хотите , функция упаковщик генератор , который может быть использован для репликации асинхронного ждать , я хотел бы проверить co.js . Кстати, функция co, очень похожая на функции асинхронного ожидания, возвращает обещание. Честно говоря, на данный момент совместимость браузера примерно одинакова как для функций генератора, так и для асинхронных функций, поэтому, если вы просто хотите использовать функцию асинхронного ожидания, вы должны использовать функции Async без co.js.
Поддержка браузеров в настоящее время довольно хороша для функций Async (по состоянию на 2017 год) во всех основных современных браузерах (Chrome, Safari и Edge), кроме IE.