9.0 KiB
title | localeTitle |
---|---|
Promises | обещания |
обещания
JavaScript однопоточный, что означает, что два бита скрипта не могут работать одновременно; они должны бежать один за другим. Promise - это объект, который представляет собой возможное завершение (или отказ) асинхронной операции и ее итоговое значение.
var promise = new Promise(function(resolve, reject) {
// do thing, then…
if (/* everything worked */) {
resolve("See, it worked!");
}
else {
reject(Error("It broke"));
}
});
В одном из этих состояний существует обещание
- Ожидание: начальное состояние, ни выполнено, ни отклонено.
- Выполнено: операция успешно завершена.
- Отклонено: операция завершилась неудачно.
Объект Promise работает как прокси-сервер для значения, которое не обязательно известно при создании обещания. Это позволяет связать обработчики с вероятным результатом успешной асинхронной операции или причиной сбоя. Это позволяет асинхронным методам возвращать такие значения, как синхронные методы: вместо немедленного возврата окончательного значения асинхронный метод возвращает обещание предоставить значение в какой-то момент в будущем.
Использование 'Then' (Promise Chaining)
Чтобы выполнить несколько асинхронных вызовов и синхронизировать их один за другим, вы можете использовать цепочку слияния. Это позволяет использовать значение из первого обещания в последующих последующих обратных вызовах.
Promise.resolve('some')
.then(function(string) { // <-- This will happen after the above Promise resolves (returning the value 'some')
return new Promise(function(resolve, reject) {
setTimeout(function() {
string += 'thing';
resolve(string);
}, 1);
});
})
.then(function(string) { // <-- This will happen after the above .then's new Promise resolves
console.log(string); // <-- Logs 'something' to the console
});
API обещаний
В классе Promise существует 4 статических метода:
- Promise.resolve
- Promise.reject
- Promise.all
- Promise.race
Обещания могут быть соединены вместе
При написании обещаний для решения конкретной проблемы вы можете связать их вместе, чтобы сформировать логику.
var add = function(x, y) {
return new Promise((resolve,reject) => {
var sum = x + y;
if (sum) {
resolve(sum);
}
else {
reject(Error("Could not add the two values!"));
}
});
};
var subtract = function(x, y) {
return new Promise((resolve, reject) => {
var sum = x - y;
if (sum) {
resolve(sum);
}
else {
reject(Error("Could not subtract the two values!"));
}
});
};
// Starting promise chain
add(2,2)
.then((added) => {
// added = 4
return subtract(added, 3);
})
.then((subtracted) => {
// subtracted = 1
return add(subtracted, 5);
})
.then((added) => {
// added = 6
return added * 2;
})
.then((result) => {
// result = 12
console.log("My result is ", result);
})
.catch((err) => {
// If any part of the chain is rejected, print the error message.
console.log(err);
});
Это полезно для использования парадигмы функционального программирования . Создавая функции для манипулирования данными, вы можете объединить их вместе, чтобы собрать окончательный результат. Если в любой точке цепочки функций значение отклоняется, цепь перейдет к ближайшему обработчику catch()
.
Для получения дополнительной информации о функциональном программировании: функциональное программирование
Генераторы функций
В последних выпусках JavaScript ввел больше способов изначально обрабатывать обещания. Одним из таких способов является генератор функций. Генераторы функций являются «правдоподобными» функциями. При использовании с Promise генераторы могут сделать использование намного проще для чтения и появиться «синхронно».
const myFirstGenerator = function* () {
const one = yield 1;
const two = yield 2;
const three = yield 3;
return 'Finished!';
}
const gen = myFirstGenerator();
Вот наш первый генератор, который вы можете видеть по синтаксису function*
. Объявленная переменная gen
не будет запускать myFirstGenerator
, но вместо этого «этот генератор будет готов к использованию».
console.log(gen.next());
// Returns { value: 1, done: false }
Когда мы запустим gen.next()
он отключит генератор и продолжит работу. Поскольку это первый раз, когда мы вызвали gen.next()
он будет работать с yield 1
и приостанавливаться до тех пор, пока мы снова не назовем gen.next()
. Когда вызывается yield 1
, он возвращает нам value
которое было получено, и независимо от того, done
ли генератор.
console.log(gen.next());
// Returns { value: 2, done: false }
console.log(gen.next());
// Returns { value: 3, done: false }
console.log(gen.next());
// Returns { value: 'Finished!', done: true }
console.log(gen.next());
// Will throw an error
Поскольку мы продолжаем называть gen.next()
он будет продолжать идти на следующий yield
и приостанавливать каждый раз. После того, как у вас больше нет yield
, он продолжит работу с остальной частью генератора, которая в этом случае просто вернется 'Finished!'
, Если вы снова вызове gen.next()
, он будет генерировать ошибку по завершении работы генератора.
Теперь представьте, что если каждый yield
в этом примере был Promise
, сам код выглядел бы крайне синхронно.
Promise.all (iterable) очень полезен для множественного запроса к другому источнику
Метод Promise.all (iterable) возвращает единственное обещание, которое разрешает, когда все обещания в итерабельном аргументе разрешены или когда аргумент итерации не содержит никаких обещаний. Он отвергает причину первого обещания, которое отвергает.
var promise1 = Promise.resolve(catSource);
var promise2 = Promise.resolve(dogSource);
var promise3 = Promise.resolve(cowSource);
Promise.all([promise1, promise2, promise3]).then(function(values) {
console.log(values);
});
// expected output: Array ["catData", "dogData", "cowData"]
Больше информации
Для получения дополнительной информации о обещаниях: обещания