Три способа понять промисы
Статья описывает три способа понимания промисов (обещаний). Ниже показан пример функции asyncFunc(), основанной на промисах:
function asyncFunc() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('DONE'), 100);
});
}
asyncFunc()
.then(x => console.log('Result: '+x));
// Output:
// Result: DONE
Так что такое промис?
- Технически, вызов asyncFunc() - это блокирующий вызов функции.
- Промис — это одновременно и контейнер для значения и эмиттер событий.
Вызов Promise-based функции является блокирующим
function asyncFunc() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('DONE'), 100);
});
}
async function main() {
const x = await asyncFunc(); // (A)
console.log('Result: '+x);
// Same as:
// asyncFunc()
// .then(x => console.log('Result: '+x));
}
main();
Функция main() - это асинхронная функция. Ее тело показывает, что происходит концептуально — как мы обычно думаем об асинхронных вычислениях:
Строка (А): Ждет пока выполнится asyncFunc().
Строка (B): Выводит результат x в консоль.
До ECMAScript 6 и генераторов вы не могли приостанавливать и возобновлять код, поэтому с помощью промисов вы помещаете все, что происходит после возобновления кода, в коллбэк. Вызов этого коллбэка аналогичен возобновлению кода.
Промис — это контейнер для асинхронно возвращаемого значения
Если функция возвращает промис, то этот промис похож на пустое значение, которое функция (как правило) в конечном итоге заполнит результатом, как только вычислит его. Вы можете смоделировать простую версию этого процесса через массив:
function asyncFunc() {
const blank = [];
setTimeout(() => blank.push('DONE'), 100);
return blank;
}
const blank = asyncFunc();
// Wait until the value has been filled in
setTimeout(() => {
const x = blank[0]; // (A)
console.log('Result: '+x);
}, 200);
С промисами вы не получаете доступ к конечным значениям с помощью [] (как в строке (А)), а используете метод then() и функцию обратного вызова.
Промис — это эмиттер событий
Другой способ взглянуть на промис — как на объект, который генерирует события.
function asyncFunc() {
const eventEmitter = { success: [] };
setTimeout(() => { // (A)
for (const handler of eventEmitter.success) {
handler('DONE');
}
}, 100);
return eventEmitter;
}
asyncFunc()
.success.push(x => console.log('Result: '+x)); // (B)
Регистрация слушателя событий (строка (B)) может быть выполнена после вызова asyncFunc(), так как коллбэк, переданный в setTimeout() (строка (A)) выполняется асинхронно, после того, как выполнится сама функция.
Обычные эмиттеры событий порождают несколько событий, начиная с момента регистрации.
Промисы же возвращают только одно значение и имеют встроенную защиту от слишком поздней регистрации: результат Promise кэшируется и передается слушателям событий, зарегистрированным после того, как промис был выполнен.
Оригинал статьи был взят с сайта getinstance.info