Le funzioni asincrone , una funzionalità di ES2017 , fanno sembrare il codice asincrono sincronizzato usando le promesse (una particolare forma di codice asincrono) e la awaitparola chiave. Notare anche negli esempi di codice sotto la parola chiave asyncdavanti alla functionparola chiave che indica una funzione asincrona / waitit. La awaitparola chiave non funzionerà senza essere in una funzione prestabilita con la asyncparola chiave. Dal momento che attualmente non vi è alcuna eccezione a ciò, il che significa che nessun livello di attesa superiore funzionerà (il livello di attesa superiore significa un'attesa al di fuori di qualsiasi funzione). Sebbene ci sia una proposta per il massimo livelloawait .
ES2017 è stato ratificato (ovvero finalizzato) come standard per JavaScript il 27 giugno 2017. Async wait potrebbe già funzionare nel tuo browser, ma in caso contrario puoi comunque utilizzare la funzionalità utilizzando un transpiler javascript come babel o traceur . Chrome 55 ha il pieno supporto delle funzioni asincrone. Quindi, se hai un browser più recente, potresti essere in grado di provare il codice qui sotto.
Vedi la tabella di compatibilità es2017 di kangax per la compatibilità del browser.
Ecco un esempio di funzione di attesa asincrona chiamata doAsyncche richiede tre pause di un secondo e stampa la differenza oraria dopo ogni pausa dall'ora di inizio:
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 la parola chiave wait viene posizionata prima di un valore di promessa (in questo caso il valore di promessa è il valore restituito dalla funzione doSomethingAsync) la parola chiave wait attende metterà in pausa l'esecuzione della chiamata di funzione, ma non metterà in pausa altre funzioni e continuerà eseguendo altro codice fino alla risoluzione della promessa. Dopo che la promessa si è risolta, scarterà il valore della promessa e puoi pensare all'espressione di attesa e promessa come ora sostituita da quel valore da scartare.
Quindi, poiché wait attende solo pause, quindi scartare un valore prima di eseguire il resto della linea, è possibile utilizzarlo per i loop e le chiamate di funzioni interne come nell'esempio seguente che raccoglie le differenze di tempo attese in un array e stampa l'array.
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)
})
La stessa funzione asincrona restituisce una promessa in modo da poterla utilizzare come promessa con il concatenamento come faccio sopra o all'interno di un'altra funzione di attesa asincrona.
La funzione sopra attenderebbe ogni risposta prima di inviare un'altra richiesta se si desidera inviare le richieste contemporaneamente è possibile utilizzare 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 la promessa può essere rifiutata, puoi racchiuderla in un catch di prova o saltare il tentativo di cattura e lasciare che l'errore si propaghi alle funzioni di cattura asincrona / wait. Dovresti stare attento a non lasciare errori promettenti, specialmente in Node.js. Di seguito sono riportati alcuni esempi che mostrano come funzionano gli errori.
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 vai qui puoi vedere le proposte finite per le prossime versioni di ECMAScript.
Un'alternativa a questa che può essere utilizzata solo con ES2015 (ES6) è quella di utilizzare una funzione speciale che avvolge una funzione del generatore. Le funzioni del generatore hanno una parola chiave yield che può essere utilizzata per replicare la parola chiave wait con una funzione circostante. La parola chiave yield e la funzione del generatore sono molto più generiche e possono fare molte più cose rispetto a ciò che fa la funzione di attesa asincrona. Se si desidera una funzione wrapper generatore che può essere utilizzato per asincrona replica attendere avrei fatto il check out co.js . A proposito, le funzioni di co molto come le funzioni di attesa asincrono restituiscono una promessa. Onestamente, sebbene a questo punto la compatibilità del browser sia pressoché identica sia per le funzioni del generatore che per le funzioni asincrone, quindi se si desidera semplicemente che la funzionalità di attesa asincrona sia necessario utilizzare le funzioni Async senza co.js.
Il supporto del browser è attualmente abbastanza buono per le funzioni Async (a partire dal 2017) in tutti i principali browser attuali (Chrome, Safari e Edge) tranne IE.