Обіцяння є державними, вони починаються як очікувані і можуть вирішуватись на:
- Виконано значення, що обчислення завершено успішно.
- відкинув значення, що обчислення не вдалося.
Обіцяючі функції повернення ніколи не повинні кидати , вони повинні повертати відхилення. Викидання функції повернення обіцянки змусить вас використовувати і a, } catch {
і a .catch
. Люди, які використовують багатообіцяючі API, не очікують, що обіцянки будуть викинуті. Якщо ви не впевнені, як функціонують API асинхронізації в JS - спочатку ознайомтеся з цією відповіддю .
1. Завантаження DOM або інша разова подія:
Отже, створювати обіцянки, як правило, означає уточнювати, коли вони вирішуються - це означає, коли вони переходять на виконану або відхилену фазу, щоб вказати, що дані є доступними (і до них можна отримати доступ .then
).
Із сучасними реалізаціями обіцянок, які підтримують Promise
конструктор, як і рідний ES6, обіцяє:
function load() {
return new Promise(function(resolve, reject) {
window.onload = resolve;
});
}
Потім ви використаєте отриману обіцянку так:
load().then(function() {
// Do things after onload
});
З бібліотеками, які підтримують відкладені (Давайте тут використаємо $ q для цього прикладу, але пізніше також будемо використовувати jQuery):
function load() {
var d = $q.defer();
window.onload = function() { d.resolve(); };
return d.promise;
}
Або за допомогою jQuery типу API, підключивши подію, що відбувається один раз:
function done() {
var d = $.Deferred();
$("#myObject").once("click",function() {
d.resolve();
});
return d.promise();
}
2. Простий зворотний виклик:
Ці API досить поширені, тому що ... зворотні виклики поширені в JS. Давайте розглянемо загальний випадок наявності onSuccess
та onFail
:
function getUserData(userId, onLoad, onFail) { …
Із сучасними реалізаціями обіцянок, які підтримують Promise
конструктор, як і рідний ES6, обіцяє:
function getUserDataAsync(userId) {
return new Promise(function(resolve, reject) {
getUserData(userId, resolve, reject);
});
}
З бібліотеками, які підтримують відкладені (Давайте тут використовувати jQuery для цього прикладу, але ми також використовували $ q вище):
function getUserDataAsync(userId) {
var d = $.Deferred();
getUserData(userId, function(res){ d.resolve(res); }, function(err){ d.reject(err); });
return d.promise();
}
jQuery також пропонує $.Deferred(fn)
форму, яка має перевагу в тому, що дозволяє нам написати вираз, який дуже тісно імітує new Promise(fn)
форму, таким чином:
function getUserDataAsync(userId) {
return $.Deferred(function(dfrd) {
getUserData(userId, dfrd.resolve, dfrd.reject);
}).promise();
}
Примітка. Тут ми використовуємо той факт, що відкладені jQuery resolve
і reject
методи "відривні"; тобто. вони пов'язані з екземпляром jQuery.Deferred (). Не всі гігієни пропонують цю функцію.
3. Зворотний виклик стилю вузла ("зворотний зв'язок"):
Зворотні виклики стилю вузла (вузли зворотного зв'язку) мають певний формат, де зворотні виклики завжди є останнім аргументом, а його першим параметром є помилка. Давайте спочатку обережно позначимо один:
getStuff("dataParam", function(err, data) { …
До:
function getStuffAsync(param) {
return new Promise(function(resolve, reject) {
getStuff(param, function(err, data) {
if (err !== null) reject(err);
else resolve(data);
});
});
}
За допомогою відкладених даних ви можете зробити наступне (давайте використовувати Q для цього прикладу, хоча Q тепер підтримує новий синтаксис, який вам слід віддати перевагу ):
function getStuffAsync(param) {
var d = Q.defer();
getStuff(param, function(err, data) {
if (err !== null) d.reject(err);
else d.resolve(data);
});
return d.promise;
}
Загалом, вам не слід занадто багато вносити вручну речі, в більшості бібліотек з обіцянками, які були розроблені з урахуванням Node, а також з власними обіцянками в Node 8+ є вбудований метод для багатообіцяючого зворотного зв'язку. Наприклад
var getStuffAsync = Promise.promisify(getStuff); // Bluebird
var getStuffAsync = Q.denodeify(getStuff); // Q
var getStuffAsync = util.promisify(getStuff); // Native promises, node only
4. Ціла бібліотека з зворотними зворотами стилю:
Тут немає жодного золотого правила, ви обіцяєте їх по черзі. Однак деякі реалізації обіцянок дозволяють робити це масово, наприклад, у Bluebird, перетворити API вузла на зворотній зв'язок в API обіцянки так само просто, як:
Promise.promisifyAll(API);
Або з власними обіцянками в Node :
const { promisify } = require('util');
const promiseAPI = Object.entries(API).map(([key, v]) => ({key, fn: promisify(v)}))
.reduce((o, p) => Object.assign(o, {[p.key]: p.fn}), {});
Примітки:
- Звичайно, коли ви знаходитесь в
.then
обробнику, вам не потрібно декламувати речі. Повернення обіцянки від .then
обробника вирішить або відхилить зі значенням цієї обіцянки. Кидати з .then
обробника також є хорошою практикою і відкине обіцянку - це відома безпека кидання обіцянок.
- В реальному
onload
випадку вам слід скористатися, addEventListener
а не використовувати onX
.