Функції асинхронізації , функція в ES2017 , дозволяють асинхронному коду виглядати синхронізуванням за допомогою обіцянок (особливої форми коду асинхронізації) та await
ключового слова. Також зауважте в прикладах коду нижче ключового слова async
перед function
ключовим словом, яке означає функцію асинхронізації / очікування. 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();
Коли ключове слово очікування буде розміщене перед значенням обіцянки (у цьому випадку значення обіцянки - це значення, повернене функцією doSomethingAsync), ключове слово очікує призупинення виконання виклику функції, але воно не зупинить жодних інших функцій, і воно продовжиться виконання іншого коду, поки обіцянка не вирішиться. Після того, як обіцянка вирішиться, вона зніме значення обіцянки, і ви можете подумати про очікування та вираз обіцянки, як тепер замінене цим розгорнутим значенням.
Отже, оскільки функція wait просто пауза очікує, а потім розгортає значення перед виконанням решти рядка, ви можете використовувати його для циклів і внутрішніх викликів функцій, як у наведеному нижче прикладі, який збирає різниці у часі, що очікується в масиві, і друкує масив.
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)
})
Якщо обіцянка, можливо, відхиляється, ви можете зафіксувати її в спробі лову або пропустити спробу влову та дозволити помилці розповсюджуватися на функцію асинхронного / очікуваного виклику. Ви повинні бути обережними, щоб не залишати помилок обіцянок не обробленими, особливо в 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), є використання спеціальної функції, яка охоплює функцію генератора. Функції генератора мають ключове слово "вихід", яке може використовуватися для тиражування ключового слова, що очікує, з оточуючою функцією. Ключове слово і функція генератора мають набагато більш загальне призначення і можуть робити багато інших речей, аніж те, що робить функція очікування асинхронізації. Якщо ви хочете , функція пакувальник генератор , який може бути використаний для реплікації асинхронного чекати , я хотів би перевірити co.js . До речі, функція co, подібно до функції асинхронізації, що очікує, повертає обіцянку. Чесно кажучи, хоча на даний момент сумісність браузера приблизно однакова як для функцій генератора, так і для функцій асинхронізації, тому якщо ви просто хочете, щоб функція async очікувала, ви повинні використовувати функції Async без co.js.
Підтримка браузера насправді досить хороша для функцій Async (станом на 2017 рік) у всіх основних поточних браузерах (Chrome, Safari та Edge), крім IE.