Для удобной работы с асинхронными функциями лучше всего использовать promises
и async/await
function thisTakes2Seconds() {
return new Promise(resolve => setTimeout(() => resolve(3), 200)); // 0.2 to avoid waiting :P
}
function thisTakes5Seconds() {
return new Promise(resolve => setTimeout(() => resolve(5), 500));
}
async function foo() {
const data = {};
data.x = await thisTakes2Seconds();
data.y = await thisTakes5Seconds();
// This will run once both promises have been resolved
console.log(data);
}
foo()
.then(() => console.log('done!')
.catch(err => console.error(err));
Если вы хотите выполнять обе функции параллельно, вы можете сделать это и подождать, пока обе функции завершат использование Promise.all
async function foo() {
const data = {};
// Promise.all returns an array where each item is the resolved
// value of the promises passed to it, maintaining the order
// So we use destructuring to assign those values
[data.x, data.y] = await Promise.all([
thisTakes2Seconds(),
thisTakes5Seconds()
]);
console.log(data);
}
Если у вас уже есть асинхронная функция, использующая обратные вызовы, вы можете легко преобразовать ее в обещания.
function myAsyncFunction(callback) {
setTimeout(() => {
callback(Math.random());
}, 200);
}
function myAsyncFunctionPromise() {
return new Promise((resolve, reject) => {
myAsyncFunction(resolve);
// If there is an error callback, just pass reject too.
});
}
Существуют библиотеки, такие как bluebird, в которых уже есть служебный метод для обещания обратного вызоваAPI.
http://bluebirdjs.com/docs/api/promise.promisify.html
Если вы используете его в браузере и нуждаетесь в поддержке устаревших, вы можете использовать babel для переноса async/await
в ES5