Асинхронные функции , функция в ES2017 , позволяют синхронизировать асинхронный код с помощью обещаний (особая форма асинхронного кода) и await
ключевое слово.Также обратите внимание на примеры кода ниже ключевого слова async
перед ключевым словом function
, которое обозначает функцию async / await.Ключевое слово await
не будет работать без функции, предварительно фиксированной с ключевым словом async
.Поскольку в настоящее время нет исключения из этого, это означает, что никакие ожидания верхнего уровня не будут работать (верхний уровень ожидает, что означает ожидание вне какой-либо функции).Хотя есть предложение для верхнего уровня await
.
ES2017 был утвержден (то есть окончательно доработан) как стандарт для JavaScript 27 июня 2017 года. Асинхронное ожидание может уже работать в вашембраузер, но если нет, вы все равно можете использовать эту функциональность с помощью транспортера javascript, например babel или traceur .Chrome 55 имеет полную поддержку асинхронных функций.Так что, если у вас более новый браузер, вы можете попробовать код ниже.
См. таблицу совместимости kangax 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)
})
Если обещание, возможно, отклоняется, вы можете заключить его в попытку try или пропустить попытку 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, очень похожая на функции асинхронного ожидания, возвращает обещание. Честно говоря, на данный момент совместимость браузера примерно одинакова как для функций генератора, так и для асинхронных функций, поэтому, если вы просто хотите использовать функцию асинхронного ожидания, вы должны использовать функции асинхронной передачи без co.js.
Поддержка браузера на самом деле довольно хороша для функций Async (по состоянию на 2017 год) во всех основных современных браузерах (Chrome, Safari и Edge), кроме IE.