As funções assíncronas , um recurso do ES2017 , fazem o código assíncrono parecer sincronizado usando promessas (uma forma específica de código assíncrono) e a await
palavra - chave. Observe também nos exemplos de código abaixo da palavra-chave async
na frente da function
palavra - chave que significa uma função assíncrona / aguardada. A await
palavra-chave não funcionará sem estar em uma função pré-fixada com a async
palavra - chave. Como atualmente não há nenhuma exceção a isso, significa que nenhum nível superior de espera funcionará (nível superior aguarda, o que significa uma espera fora de qualquer função). Embora exista uma proposta de nível superiorawait
.
O ES2017 foi ratificado (ou seja, finalizado) como padrão para JavaScript em 27 de junho de 2017. O Async aguardar já pode funcionar no seu navegador, mas, se não, você ainda pode usar a funcionalidade usando um transpilador javascript, como babel ou traceur . O Chrome 55 oferece suporte total às funções assíncronas. Portanto, se você tiver um navegador mais novo, poderá experimentar o código abaixo.
Consulte a tabela de compatibilidade es2017 da kangax para obter compatibilidade com o navegador.
Aqui está um exemplo de função de espera assíncrona chamada, doAsync
que realiza três pausas de um segundo e imprime a diferença horária após cada pausa a partir da hora de início:
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();
Quando a palavra-chave wait for colocada antes de um valor prometido (nesse caso, o valor prometido é o valor retornado pela função doSomethingAsync), a palavra-chave wait aguardará a execução da chamada da função, mas não pausará nenhuma outra função e continuará executando outro código até que a promessa seja resolvida. Depois que a promessa for resolvida, ela desembrulhará o valor da promessa e você poderá pensar na expressão de espera e promessa como sendo substituída agora por esse valor desembrulhado.
Portanto, uma vez que wait apenas pausa, espera e, em seguida, desembrulha um valor antes de executar o restante da linha, você pode usá-lo para loops e chamadas de funções internas, como no exemplo abaixo, que coleta diferenças de tempo esperadas em uma matriz e imprime a matriz.
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)
})
A própria função assíncrona retorna uma promessa para que você possa usá-la como encadeamento, como eu faço acima ou dentro de outra função de espera assíncrona.
A função acima aguardaria cada resposta antes de enviar outra solicitação, se você quiser enviar as solicitações simultaneamente, pode usar 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)
})
Se a promessa possivelmente rejeitar, você pode envolvê-la em uma tentativa de captura ou pular a tentativa de captura e deixar o erro se propagar para a chamada de captura de funções assíncronas / aguardadas. Você deve ter cuidado para não deixar erros de promessa sem tratamento, especialmente no Node.js. Abaixo estão alguns exemplos que mostram como os erros funcionam.
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)
Se você for aqui, poderá ver as propostas finalizadas para as próximas versões do ECMAScript.
Uma alternativa a isso que pode ser usada apenas com o ES2015 (ES6) é usar uma função especial que envolve uma função de gerador. As funções do gerador têm uma palavra-chave yield que pode ser usada para replicar a palavra-chave wait com uma função circundante. A palavra-chave yield e a função de gerador são muito mais genéricas e podem fazer muito mais coisas do que a função de espera assíncrona. Se você quer um invólucro função de gerador que pode ser usado para assíncrono replicar esperam que eu gostaria check-out co.js . A propósito, as funções co, assim como as funções de espera assíncrona, retornam uma promessa. Honestamente, neste ponto, a compatibilidade do navegador é praticamente a mesma para as funções de gerador e funções assíncronas; portanto, se você deseja apenas a funcionalidade de espera assíncrona, deve usar as funções assíncronas sem co.js.
Atualmente, o suporte ao navegador é muito bom para as funções Async (a partir de 2017) em todos os principais navegadores atuais (Chrome, Safari e Edge), exceto no IE.