Promise (обÑÑно Ð¸Ñ Ñак и назÑваÑÑ Â«Ð¿ÑомиÑÑ») â пÑедоÑÑавлÑÑÑ ÑдобнÑй ÑпоÑоб оÑганизаÑии аÑÐ¸Ð½Ñ Ñонного кода.
Ð ÑовÑеменном JavaScript пÑомиÑÑ ÑаÑÑо иÑполÑзÑÑÑÑÑ Ð² Ñом ÑиÑле и неÑвно, пÑи помоÑи генеÑаÑоÑов, но об ÑÑом ÑÑÑÑ Ð¿Ð¾Ð·Ð¶Ðµ.
ЧÑо Ñакое Promise?
Promise â ÑÑо ÑпеÑиалÑнÑй обÑекÑ, коÑоÑÑй ÑодеÑÐ¶Ð¸Ñ ÑÐ²Ð¾Ñ ÑоÑÑоÑние. ÐнаÑале pending («ожидание»), заÑем â одно из: fulfilled («вÑполнено ÑÑпеÑно») или rejected («вÑполнено Ñ Ð¾Ñибкой»).
Ðа promise можно навеÑиваÑÑ ÐºÐ¾Ð»Ð±Ñки двÑÑ
Ñипов:
onFulfilledâ ÑÑабаÑÑваÑÑ, когдаpromiseв ÑоÑÑоÑнии «вÑполнен ÑÑпеÑно».onRejectedâ ÑÑабаÑÑваÑÑ, когдаpromiseв ÑоÑÑоÑнии «вÑполнен Ñ Ð¾Ñибкой».
СпоÑоб иÑполÑзованиÑ, в обÑÐ¸Ñ ÑеÑÑÐ°Ñ , Ñакой:
- Ðод, коÑоÑÐ¾Ð¼Ñ Ð½Ð°Ð´Ð¾ ÑделаÑÑ ÑÑо-Ñо аÑинÑ
Ñонно, ÑоздаÑÑ Ð¾Ð±ÑекÑ
promiseи возвÑаÑÐ°ÐµÑ ÐµÐ³Ð¾. - ÐнеÑний код, полÑÑив
promise, навеÑÐ¸Ð²Ð°ÐµÑ Ð½Ð° него обÑабоÑÑики. - Ðо завеÑÑении пÑоÑеÑÑа аÑинÑ
ÑоннÑй код пеÑеводиÑ
promiseв ÑоÑÑоÑниеfulfilled(Ñ ÑезÑлÑÑаÑом) илиrejected(Ñ Ð¾Ñибкой). ÐÑи ÑÑом авÑомаÑиÑеÑки вÑзÑваÑÑÑÑ ÑооÑвеÑÑÑвÑÑÑие обÑабоÑÑики во внеÑнем коде.
СинÑакÑÐ¸Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Promise:
var promise = new Promise(function(resolve, reject) {
// ÐÑа ÑÑнкÑÐ¸Ñ Ð±ÑÐ´ÐµÑ Ð²Ñзвана авÑомаÑиÑеÑки
// Рней можно делаÑÑ Ð»ÑбÑе аÑинÑ
ÑоннÑе опеÑаÑии,
// Ркогда они завеÑÑаÑÑÑ â нÑжно вÑзваÑÑ Ð¾Ð´Ð½Ð¾ из:
// resolve(ÑезÑлÑÑаÑ) пÑи ÑÑпеÑном вÑполнении
// reject(оÑибка) пÑи оÑибке
})
УнивеÑÑалÑнÑй меÑод Ð´Ð»Ñ Ð½Ð°Ð²ÐµÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±ÑабоÑÑиков:
promise.then(onFulfilled, onRejected)
onFulfilledâ ÑÑнкÑиÑ, коÑоÑÐ°Ñ Ð±ÑÐ´ÐµÑ Ð²Ñзвана Ñ ÑезÑлÑÑаÑом пÑиresolve.onRejectedâ ÑÑнкÑиÑ, коÑоÑÐ°Ñ Ð±ÑÐ´ÐµÑ Ð²Ñзвана Ñ Ð¾Ñибкой пÑиreject.
С его помоÑÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ назнаÑиÑÑ ÐºÐ°Ðº оба обÑабоÑÑика ÑÑазÑ, Ñак и ÑолÑко один:
// onFulfilled ÑÑабоÑÐ°ÐµÑ Ð¿Ñи ÑÑпеÑном вÑполнении
promise.then(onFulfilled)
// onRejected ÑÑабоÑÐ°ÐµÑ Ð¿Ñи оÑибке
promise.then(null, onRejected)
ÐÐ»Ñ Ñого, ÑÑÐ¾Ð±Ñ Ð¿Ð¾ÑÑавиÑÑ Ð¾Ð±ÑабоÑÑик ÑолÑко на оÑибкÑ, вмеÑÑо .then(null, onRejected) можно напиÑаÑÑ .catch(onRejected) â ÑÑо Ñо же Ñамое.
throw â Ñо же Ñамое, ÑÑо rejectÐÑли в ÑÑнкÑии пÑомиÑа пÑоиÑÑ
Ð¾Ð´Ð¸Ñ ÑинÑ
ÑоннÑй throw (или Ð¸Ð½Ð°Ñ Ð¾Ñибка), Ñо вÑзÑваеÑÑÑ reject:
'use strict';
let p = new Promise((resolve, reject) => {
// Ñо же ÑÑо reject(new Error("o_O"))
throw new Error("o_O");
})
p.catch(alert); // Error: o_O
ÐоÑмоÑÑим, как ÑÑо вÑглÑÐ´Ð¸Ñ Ð²Ð¼ÐµÑÑе, на пÑоÑÑом пÑимеÑе.
ÐÑÐ¸Ð¼ÐµÑ Ñ setTimeout
ÐозÑмÑм setTimeout в каÑеÑÑве аÑинÑ
Ñонной опеÑаÑии, коÑоÑÐ°Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° ÑеÑез некоÑоÑое вÑÐµÐ¼Ñ ÑÑпеÑно завеÑÑиÑÑÑÑ Ñ ÑезÑлÑÑаÑом «result»:
'use strict';
// СоздаÑÑÑÑ Ð¾Ð±ÑÐµÐºÑ promise
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
// пеÑеведÑÑ Ð¿ÑÐ¾Ð¼Ð¸Ñ Ð² ÑоÑÑоÑние fulfilled Ñ ÑезÑлÑÑаÑом "result"
resolve("result");
}, 1000);
});
// promise.then навеÑÐ¸Ð²Ð°ÐµÑ Ð¾Ð±ÑабоÑÑики на ÑÑпеÑнÑй ÑезÑлÑÑÐ°Ñ Ð¸Ð»Ð¸ оÑибкÑ
promise
.then(
result => {
// пеÑÐ²Ð°Ñ ÑÑнкÑиÑ-обÑабоÑÑик - запÑÑÑиÑÑÑ Ð¿Ñи вÑзове resolve
alert("Fulfilled: " + result); // result - аÑгÑÐ¼ÐµÐ½Ñ resolve
},
error => {
// вÑоÑÐ°Ñ ÑÑнкÑÐ¸Ñ - запÑÑÑиÑÑÑ Ð¿Ñи вÑзове reject
alert("Rejected: " + error); // error - аÑгÑÐ¼ÐµÐ½Ñ reject
}
);
Ð ÑезÑлÑÑаÑе запÑÑка кода вÑÑе â ÑеÑез 1 ÑекÑÐ½Ð´Ñ Ð²ÑведеÑÑÑ Â«Fulfilled: result».
РеÑли Ð±Ñ Ð²Ð¼ÐµÑÑо resolve("result") бÑл вÑзов reject("error"), Ñо вÑвелоÑÑ Ð±Ñ Â«Rejected: error». ÐпÑоÑем, как пÑавило, еÑли пÑи вÑполнении возникла пÑоблема, Ñо reject вÑзÑваÑÑ Ð½Ðµ Ñо ÑÑÑокой, а Ñ Ð¾Ð±ÑекÑом оÑибки Ñипа new Error:
// ÐÑÐ¾Ñ promise завеÑÑиÑÑÑ Ñ Ð¾Ñибкой ÑеÑез 1 ÑекÑндÑ
var promise = new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error("вÑÐµÐ¼Ñ Ð²ÑÑло!"));
}, 1000);
});
promise
.then(
result => alert("Fulfilled: " + result),
error => alert("Rejected: " + error.message) // Rejected: вÑÐµÐ¼Ñ Ð²ÑÑло!
);
ÐонеÑно, вмеÑÑо setTimeout внÑÑÑи ÑÑнкÑии пÑомиÑа Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¸ запÑÐ¾Ñ Ðº ÑеÑвеÑÑ Ð¸ ожидание ввода полÑзоваÑелÑ, или дÑÑгой аÑинÑ
ÑоннÑй пÑоÑеÑÑ. Ðлавное, ÑÑÐ¾Ð±Ñ Ð¿Ð¾ ÑÐ²Ð¾ÐµÐ¼Ñ Ð·Ð°Ð²ÐµÑÑÐµÐ½Ð¸Ñ Ð¾Ð½ вÑзвал resolve или reject, коÑоÑÑе пеÑедадÑÑ ÑезÑлÑÑÐ°Ñ Ð¾Ð±ÑабоÑÑикам.
ФÑнкÑии resolve/reject пÑинимаÑÑ Ñовно один аÑгÑÐ¼ÐµÐ½Ñ â ÑезÑлÑÑаÑ/оÑибкÑ.
Ðменно он пеÑедаÑÑÑÑ Ð¾Ð±ÑабоÑÑикам в .then, как можно видеÑÑ Ð² пÑимеÑаÑ
вÑÑе.
Promise поÑле reject/resolve â неизменнÑ
ÐамеÑим, ÑÑо поÑле вÑзова resolve/reject пÑÐ¾Ð¼Ð¸Ñ Ñже не Ð¼Ð¾Ð¶ÐµÑ Â«Ð¿ÐµÑедÑмаÑÑ».
Ðогда пÑÐ¾Ð¼Ð¸Ñ Ð¿ÐµÑÐµÑ Ð¾Ð´Ð¸Ñ Ð² ÑоÑÑоÑние «вÑполнен» â Ñ ÑезÑлÑÑаÑом (resolve) или оÑибкой (reject) â ÑÑо навÑегда.
ÐапÑимеÑ:
'use strict';
let promise = new Promise((resolve, reject) => {
// ÑеÑез 1 ÑекÑÐ½Ð´Ñ Ð³Ð¾Ñов ÑезÑлÑÑаÑ: result
setTimeout(() => resolve("result"), 1000);
// ÑеÑез 2 ÑекÑÐ½Ð´Ñ â reject Ñ Ð¾Ñибкой, он бÑÐ´ÐµÑ Ð¿ÑоигноÑиÑован
setTimeout(() => reject(new Error("ignored")), 2000);
});
promise
.then(
result => alert("Fulfilled: " + result), // ÑÑабоÑаеÑ
error => alert("Rejected: " + error) // не ÑÑабоÑаеÑ
);
Ð ÑезÑлÑÑаÑе вÑзова ÑÑого кода ÑÑабоÑÐ°ÐµÑ ÑолÑко пеÑвÑй обÑабоÑÑик then, Ñак как поÑле вÑзова resolve пÑÐ¾Ð¼Ð¸Ñ Ñже полÑÑил ÑоÑÑоÑние (Ñ ÑезÑлÑÑаÑом), и в далÑнейÑем его Ñже ниÑÑо не измениÑ.
ÐоÑледÑÑÑие вÑÐ·Ð¾Ð²Ñ resolve/reject бÑдÑÑ Ð¿ÑоÑÑо пÑоигноÑиÑованÑ.
Ð Ñак â наобоÑоÑ, оÑибка бÑÐ´ÐµÑ ÑанÑÑе:
'use strict';
let promise = new Promise((resolve, reject) => {
// reject вÑзван ÑанÑÑе, resolve бÑÐ´ÐµÑ Ð¿ÑоигноÑиÑован
setTimeout(() => reject(new Error("error")), 1000);
setTimeout(() => resolve("ignored"), 2000);
});
promise
.then(
result => alert("Fulfilled: " + result), // не ÑÑабоÑаеÑ
error => alert("Rejected: " + error) // ÑÑабоÑаеÑ
);
ÐÑомиÑиÑикаÑиÑ
ÐÑомиÑиÑикаÑÐ¸Ñ â ÑÑо когда беÑÑÑ Ð°ÑÐ¸Ð½Ñ ÑоннÑÑ ÑÑнкÑионалÑноÑÑÑ Ð¸ делаÑÑ Ð´Ð»Ñ Ð½ÐµÑ Ð¾Ð±ÑÑÑкÑ, возвÑаÑаÑÑÑÑ Ð¿ÑомиÑ.
ÐоÑле пÑомиÑиÑикаÑии иÑполÑзование ÑÑнкÑионалÑноÑÑи заÑаÑÑÑÑ ÑÑановиÑÑÑ Ð³Ð¾Ñаздо Ñдобнее.
РкаÑеÑÑве пÑимеÑа Ñделаем ÑакÑÑ Ð¾Ð±ÑÑÑÐºÑ Ð´Ð»Ñ Ð·Ð°Ð¿ÑоÑов пÑи помоÑи XMLHttpRequest.
ФÑнкÑÐ¸Ñ httpGet(url) бÑÐ´ÐµÑ Ð²Ð¾Ð·Ð²ÑаÑаÑÑ Ð¿ÑомиÑ, коÑоÑÑй пÑи ÑÑпеÑной загÑÑзке даннÑÑ
Ñ url бÑÐ´ÐµÑ Ð¿ÐµÑеÑ
одиÑÑ Ð² fulfilled Ñ ÑÑими даннÑми, а пÑи оÑибке â в rejected Ñ Ð¸Ð½ÑоÑмаÑией об оÑибке:
function httpGet(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function() {
if (this.status == 200) {
resolve(this.response);
} else {
var error = new Error(this.statusText);
error.code = this.status;
reject(error);
}
};
xhr.onerror = function() {
reject(new Error("Network Error"));
};
xhr.send();
});
}
Ðак видно, внÑÑÑи ÑÑнкÑии обÑÐµÐºÑ XMLHttpRequest ÑоздаÑÑÑÑ Ð¸ оÑÑÑлаеÑÑÑ ÐºÐ°Ðº обÑÑно, пÑи onload/onerror вÑзÑваÑÑÑÑ, ÑооÑвеÑÑÑвенно, resolve (пÑи ÑÑаÑÑÑе 200) или reject.
ÐÑполÑзование:
httpGet("/article/promise/user.json")
.then(
response => alert(`Fulfilled: ${response}`),
error => alert(`Rejected: ${error}`)
);
fetchÐамеÑим, ÑÑо ÑÑд ÑовÑеменнÑÑ
бÑаÑзеÑов Ñже поддеÑÐ¶Ð¸Ð²Ð°ÐµÑ fetch â новÑй вÑÑÑоеннÑй меÑод Ð´Ð»Ñ AJAX-запÑоÑов, пÑизваннÑй замениÑÑ XMLHttpRequest. Ðн гоÑаздо моÑнее, Ñем httpGet. Ð â да, ÑÑÐ¾Ñ Ð¼ÐµÑод иÑполÑзÑÐµÑ Ð¿ÑомиÑÑ. ÐолиÑил Ð´Ð»Ñ Ð½ÐµÐ³Ð¾ доÑÑÑпен на https://github.com/github/fetch.
ЦепоÑки пÑомиÑов
«Чейнинг» (chaining), Ñо еÑÑÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑÑ ÑÑÑоиÑÑ Ð°ÑÐ¸Ð½Ñ ÑоннÑе ÑепоÑки из пÑомиÑов â пожалÑй, оÑÐ½Ð¾Ð²Ð½Ð°Ñ Ð¿ÑиÑина, из-за коÑоÑой ÑÑÑеÑÑвÑÑÑ Ð¸ акÑивно иÑполÑзÑÑÑÑÑ Ð¿ÑомиÑÑ.
ÐапÑимеÑ, Ð¼Ñ Ñ Ð¾Ñим по оÑеÑеди:
- ÐагÑÑзиÑÑ Ð´Ð°Ð½Ð½Ñе поÑеÑиÑÐµÐ»Ñ Ñ ÑеÑвеÑа (аÑÐ¸Ð½Ñ Ñонно).
- ÐаÑем оÑпÑавиÑÑ Ð·Ð°Ð¿ÑÐ¾Ñ Ð¾ нÑм на github (аÑÐ¸Ð½Ñ Ñонно).
- Ðогда ÑÑо бÑÐ´ÐµÑ Ð³Ð¾Ñово, вÑвеÑÑи его github-аваÑÐ°Ñ Ð½Ð° ÑкÑан (аÑÐ¸Ð½Ñ Ñонно).
- â¦Ð ÑделаÑÑ ÐºÐ¾Ð´ ÑаÑÑиÑÑемÑм, ÑÑÐ¾Ð±Ñ ÑепоÑÐºÑ Ð¼Ð¾Ð¶Ð½Ð¾ бÑло легко пÑодолжиÑÑ.
ÐÐ¾Ñ ÐºÐ¾Ð´ Ð´Ð»Ñ ÑÑого, иÑполÑзÑÑÑий ÑÑнкÑÐ¸Ñ httpGet, опиÑаннÑÑ Ð²ÑÑе:
'use strict';
// ÑделаÑÑ Ð·Ð°Ð¿ÑоÑ
httpGet('/article/promise/user.json')
// 1. ÐолÑÑиÑÑ Ð´Ð°Ð½Ð½Ñе о полÑзоваÑеле в JSON и пеÑедаÑÑ Ð´Ð°Ð»ÑÑе
.then(response => {
console.log(response);
let user = JSON.parse(response);
return user;
})
// 2. ÐолÑÑиÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ñ github
.then(user => {
console.log(user);
return httpGet(`https://api.github.com/users/${user.name}`);
})
// 3. ÐÑвеÑÑи аваÑÐ°Ñ Ð½Ð° 3 ÑекÑÐ½Ð´Ñ (можно Ñ Ð°Ð½Ð¸Ð¼Ð°Ñией)
.then(githubUser => {
console.log(githubUser);
githubUser = JSON.parse(githubUser);
let img = new Image();
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.appendChild(img);
setTimeout(() => img.remove(), 3000); // (*)
});
Самое главное в ÑÑом коде â поÑледоваÑелÑноÑÑÑ Ð²Ñзовов:
httpGet(...)
.then(...)
.then(...)
.then(...)
ÐÑи Ñейнинге, Ñо еÑÑÑ Ð¿Ð¾ÑледоваÑелÑнÑÑ
вÑзоваÑ
.thenâ¦thenâ¦then, в каждÑй ÑледÑÑÑий then пеÑеÑ
Ð¾Ð´Ð¸Ñ ÑезÑлÑÑÐ°Ñ Ð¾Ñ Ð¿ÑедÑдÑÑего. ÐÑÐ·Ð¾Ð²Ñ console.log оÑÑавленÑ, ÑÑÐ¾Ð±Ñ Ð¿Ñи запÑÑке можно бÑло поÑмоÑÑеÑÑ ÐºÐ¾Ð½ÐºÑеÑнÑе знаÑениÑ, Ñ
оÑÑ Ð¾Ð½Ð¸ здеÑÑ Ð¸ не оÑÐµÐ½Ñ Ð²Ð°Ð¶Ð½Ñ.
ÐÑли оÑеÑедной then веÑнÑл пÑомиÑ, Ñо далее по ÑепоÑке бÑÐ´ÐµÑ Ð¿ÐµÑедан не Ñам ÑÑÐ¾Ñ Ð¿ÑомиÑ, а его ÑезÑлÑÑаÑ.
Ркоде вÑÑе:
- ФÑнкÑÐ¸Ñ Ð² пеÑвом
thenвозвÑаÑÐ°ÐµÑ Â«Ð¾Ð±ÑÑное» знаÑениеuser. ÐÑо знаÑиÑ, ÑÑоthenвозвÑаÑÐ¸Ñ Ð¿ÑÐ¾Ð¼Ð¸Ñ Ð² ÑоÑÑоÑнии «вÑполнен» Ñuserв каÑеÑÑве ÑезÑлÑÑаÑа. Ðн ÑÑÐ°Ð½ÐµÑ Ð°ÑгÑменÑом в ÑледÑÑÑемthen. - ФÑнкÑÐ¸Ñ Ð²Ð¾ вÑоÑом
thenвозвÑаÑÐ°ÐµÑ Ð¿ÑÐ¾Ð¼Ð¸Ñ (ÑезÑлÑÑÐ°Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ вÑзоваhttpGet). Ðогда он бÑÐ´ÐµÑ Ð·Ð°Ð²ÐµÑÑÑн (Ð¼Ð¾Ð¶ÐµÑ Ð¿ÑойÑи какое-Ñо вÑемÑ), Ñо бÑÐ´ÐµÑ Ð²Ñзван ÑледÑÑÑийthenÑ ÐµÐ³Ð¾ ÑезÑлÑÑаÑом. - ТÑеÑий
thenниÑего не возвÑаÑаеÑ.
Ð¡Ñ ÐµÐ¼Ð°ÑиÑно его ÑабоÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ изобÑазиÑÑ Ñак:
ÐнаÑком «пеÑоÑнÑе ÑаÑÑ» помеÑÐµÐ½Ñ Ð¿ÐµÑÐ¸Ð¾Ð´Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ, коÑоÑÑÑ
вÑего два: в иÑÑ
одном httpGet и в подвÑзове далее по ÑепоÑке.
ÐÑли then возвÑаÑÐ°ÐµÑ Ð¿ÑомиÑ, Ñо до его вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð¶ÐµÑ Ð¿ÑойÑи некоÑоÑое вÑемÑ, оÑÑавÑаÑÑÑ ÑаÑÑÑ ÑепоÑки бÑÐ´ÐµÑ Ð¶Ð´Ð°ÑÑ.
То еÑÑÑ, логика доволÑно пÑоÑÑа:
- Ркаждом
thenÐ¼Ñ Ð¿Ð¾Ð»ÑÑаем ÑекÑÑий ÑезÑлÑÑÐ°Ñ ÑабоÑÑ. - Ðожно его обÑабоÑаÑÑ ÑинÑ
Ñонно и веÑнÑÑÑ ÑезÑлÑÑÐ°Ñ (напÑимеÑ, пÑимениÑÑ
JSON.parse). Ðли же, еÑли нÑжна аÑÐ¸Ð½Ñ ÑÐ¾Ð½Ð½Ð°Ñ Ð¾Ð±ÑабоÑка â иниÑииÑоваÑÑ ÐµÑ Ð¸ веÑнÑÑÑ Ð¿ÑомиÑ.
ÐбÑаÑим внимание, ÑÑо поÑледний then в наÑем пÑимеÑе ниÑего не возвÑаÑаеÑ. ÐÑли Ð¼Ñ Ñ
оÑим, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ñле setTimeout (*) аÑинÑ
ÑÐ¾Ð½Ð½Ð°Ñ ÑепоÑка могла бÑÑÑ Ð¿Ñодолжена, Ñо поÑледний then Ñоже должен веÑнÑÑÑ Ð¿ÑомиÑ. ÐÑо обÑее пÑавило: еÑли внÑÑÑи then ÑÑаÑÑÑÐµÑ Ð½Ð¾Ð²Ñй аÑинÑ
ÑоннÑй пÑоÑеÑÑ, Ñо Ð´Ð»Ñ Ñого, ÑÑÐ¾Ð±Ñ Ð¾ÑÑавÑаÑÑÑ ÑаÑÑÑ ÑепоÑки вÑполнилаÑÑ Ð¿Ð¾Ñле его оконÑаниÑ, Ð¼Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð²ÐµÑнÑÑÑ Ð¿ÑомиÑ.
Рданном ÑлÑÑае пÑÐ¾Ð¼Ð¸Ñ Ð´Ð¾Ð»Ð¶ÐµÐ½ пеÑейÑи в ÑоÑÑоÑние «вÑполнен» поÑле ÑÑабаÑÑÐ²Ð°Ð½Ð¸Ñ setTimeout.
СÑÑÐ¾ÐºÑ (*) Ð´Ð»Ñ ÑÑого нÑжно пеÑепиÑаÑÑ Ñак:
.then(githubUser => {
...
// вмеÑÑо setTimeout(() => img.remove(), 3000); (*)
return new Promise((resolve, reject) => {
setTimeout(() => {
img.remove();
// поÑле ÑаймаÑÑа â вÑзов resolve,
// можно без ÑезÑлÑÑаÑа, ÑÑÐ¾Ð±Ñ ÑпÑавление пеÑеÑло в ÑледÑÑÑий then
// (или можно пеÑедаÑÑ Ð´Ð°Ð½Ð½Ñе полÑзоваÑÐµÐ»Ñ Ð´Ð°Ð»ÑÑе по ÑепоÑке)
resolve();
}, 3000);
});
})
ТепеÑÑ, еÑли к ÑепоÑке добавиÑÑ ÐµÑÑ then, Ñо он бÑÐ´ÐµÑ Ð²Ñзван поÑле оконÑÐ°Ð½Ð¸Ñ setTimeout.
ÐеÑÐµÑ Ð²Ð°Ñ Ð¾Ñибок
ÐÑÑе Ð¼Ñ ÑаÑÑмоÑÑели «идеалÑнÑй ÑлÑÑай» вÑполнениÑ, когда оÑибок неÑ.
Ð ÑÑо, еÑли github не оÑвеÑаеÑ? Ðли JSON.parse бÑоÑил ÑинÑакÑиÑеÑкÑÑ Ð¾ÑÐ¸Ð±ÐºÑ Ð¿Ñи обÑабоÑке даннÑÑ ?
Ðа мало ли, где оÑибкаâ¦
ÐÑавило здеÑÑ Ð¾ÑÐµÐ½Ñ Ð¿ÑоÑÑое.
ÐÑи возникновении оÑибки â она оÑпÑавлÑеÑÑÑ Ð² ближайÑий обÑабоÑÑик onRejected.
Такой обÑабоÑÑик нÑжно поÑÑавиÑÑ ÑеÑез вÑоÑой аÑгÑÐ¼ÐµÐ½Ñ .then(..., onRejected) или, ÑÑо Ñо же Ñамое, ÑеÑез .catch(onRejected).
ЧÑÐ¾Ð±Ñ Ð¿Ð¾Ð¹Ð¼Ð°ÑÑ Ð²ÑевозможнÑе оÑибки, коÑоÑÑе возникнÑÑ Ð¿Ñи загÑÑзке и обÑабоÑке даннÑÑ
, добавим catch в ÐºÐ¾Ð½ÐµÑ Ð½Ð°Ñей ÑепоÑки:
'use strict';
// в httpGet обÑаÑимÑÑ Ðº неÑÑÑеÑÑвÑÑÑей ÑÑÑаниÑе
httpGet('/page-not-exists')
.then(response => JSON.parse(response))
.then(user => httpGet(`https://api.github.com/users/${user.name}`))
.then(githubUser => {
githubUser = JSON.parse(githubUser);
let img = new Image();
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.appendChild(img);
return new Promise((resolve, reject) => {
setTimeout(() => {
img.remove();
resolve();
}, 3000);
});
})
.catch(error => {
alert(error); // Error: Not Found
});
РпÑимеÑе вÑÑе оÑибка Ð²Ð¾Ð·Ð½Ð¸ÐºÐ°ÐµÑ Ð² пеÑвом же httpGet, но catch Ñ Ñем же ÑÑпеÑ
ом поймал Ð±Ñ Ð¾ÑÐ¸Ð±ÐºÑ Ð²Ð¾ вÑоÑом httpGet или в JSON.parse.
ÐÑинÑип оÑÐµÐ½Ñ Ð¿Ð¾Ñ
ож на обÑÑнÑй try..catch: Ð¼Ñ Ð´ÐµÐ»Ð°ÐµÐ¼ аÑинÑ
ÑоннÑÑ ÑепоÑÐºÑ Ð¸Ð· .then, а заÑем, в Ñом меÑÑе кода, где нÑжно пеÑеÑ
ваÑиÑÑ Ð¾Ñибки, вÑзÑваем .catch(onRejected).
catch?ÐбÑабоÑÑик .catch(onRejected) полÑÑÐ°ÐµÑ Ð¾ÑÐ¸Ð±ÐºÑ Ð¸ должен обÑабоÑаÑÑ ÐµÑ.
ÐÑÑÑ Ð´Ð²Ð° ваÑианÑа ÑазвиÑÐ¸Ñ ÑобÑÑий:
- ÐÑли оÑибка не кÑиÑиÑнаÑ, Ñо
onRejectedвозвÑаÑÐ°ÐµÑ Ð·Ð½Ð°Ñение ÑеÑезreturn, и ÑпÑавление пеÑÐµÑ Ð¾Ð´Ð¸Ñ Ð² ближайÑий.then(onFulfilled). - ÐÑли пÑодолжиÑÑ Ð²Ñполнение Ñ Ñакой оÑибкой нелÑзÑ, Ñо он делаеÑ
throw, и Ñогда оÑибка пеÑÐµÑ Ð¾Ð´Ð¸Ñ Ð² ÑледÑÑÑий ближайÑий.catch(onRejected).
ÐÑо Ñакже поÑ
оже на обÑÑнÑй try..catch â в блоке catch оÑибка либо обÑабаÑÑваеÑÑÑ, и Ñогда вÑполнение кода пÑодолжаеÑÑÑ ÐºÐ°Ðº обÑÑно, либо он Ð´ÐµÐ»Ð°ÐµÑ throw. СÑÑеÑÑвенное оÑлиÑие â в Ñом, ÑÑо пÑомиÑÑ Ð°ÑинÑ
ÑоннÑе, поÑÑÐ¾Ð¼Ñ Ð¿Ñи оÑÑÑÑÑÑвии внеÑнего .catch оÑибка не «вÑваливаеÑÑÑ» в конÑÐ¾Ð»Ñ Ð¸ не «ÑбиваеÑ» ÑкÑипÑ.
ÐÐµÐ´Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾, ÑÑо новÑй обÑабоÑÑик .catch бÑÐ´ÐµÑ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½ в ÑепоÑÐºÑ Ð¿Ð¾Ð·Ð¶Ðµ.
ÐÑомиÑÑ Ð² деÑалÑÑ
СамÑм оÑновнÑм иÑÑоÑником инÑоÑмаÑии по пÑомиÑам ÑвлÑеÑÑÑ, ÑазÑмееÑÑÑ, ÑÑандаÑÑ.
ЧÑÐ¾Ð±Ñ Ð½Ð°Ñе понимание пÑомиÑов бÑло полнÑм, и Ð¼Ñ Ð¼Ð¾Ð³Ð»Ð¸ Ñ Ð»ÑгкоÑÑÑÑ ÑазÑеÑаÑÑ ÑложнÑе ÑиÑÑаÑии, поÑмоÑÑим внимаÑелÑнее, ÑÑо Ñакое пÑÐ¾Ð¼Ð¸Ñ Ð¸ как он ÑабоÑаеÑ, но Ñже не в обÑÐ¸Ñ ÑÐ»Ð¾Ð²Ð°Ñ , а деÑалÑно, в ÑооÑвеÑÑÑвии Ñо ÑÑандаÑÑом ECMAScript.
СоглаÑно ÑÑандаÑÑÑ, Ñ Ð¾Ð±ÑекÑа new Promise(executor) пÑи Ñоздании еÑÑÑ ÑеÑÑÑе внÑÑÑенниÑ
ÑвойÑÑва:
PromiseStateâ ÑоÑÑоÑние, внаÑале «pending».PromiseResultâ ÑезÑлÑÑаÑ, пÑи Ñоздании знаÑÐµÐ½Ð¸Ñ Ð½ÐµÑ.PromiseFulfillReactionsâ ÑпиÑок ÑÑнкÑий-обÑабоÑÑиков ÑÑпеÑного вÑполнениÑ.PromiseRejectReactionsâ ÑпиÑок ÑÑнкÑий-обÑабоÑÑиков оÑибки.
Ðогда ÑÑнкÑиÑ-executor вÑзÑÐ²Ð°ÐµÑ reject или resolve, Ñо PromiseState ÑÑановиÑÑÑ "resolved" или "rejected", а вÑе ÑÑнкÑии-обÑабоÑÑики из ÑооÑвеÑÑÑвÑÑÑего ÑпиÑка пеÑемеÑаÑÑÑÑ Ð² ÑпеÑиалÑнÑÑ ÑиÑÑемнÑÑ Ð¾ÑеÑÐµÐ´Ñ "PromiseJobs".
ÐÑа оÑеÑÐµÐ´Ñ Ð°Ð²ÑомаÑиÑеÑки вÑполнÑеÑÑÑ, когда инÑеÑпÑеÑаÑоÑÑ Â«Ð½ÐµÑего делаÑÑ». ÐнаÑе говоÑÑ, вÑе ÑÑнкÑии-обÑабоÑÑики вÑполнÑÑÑÑ Ð°ÑинÑ
Ñонно, одна за дÑÑгой, по завеÑÑении ÑекÑÑего кода, пÑимеÑно как setTimeout(..,0).
ÐÑклÑÑение из ÑÑого пÑавила â еÑли resolve возвÑаÑÐ°ÐµÑ Ð´ÑÑгой Promise. Тогда далÑнейÑее вÑполнение Ð¾Ð¶Ð¸Ð´Ð°ÐµÑ ÐµÐ³Ð¾ ÑезÑлÑÑаÑа (в оÑеÑÐµÐ´Ñ Ð¿Ð¾Ð¼ÐµÑаеÑÑÑ ÑпеÑиалÑÐ½Ð°Ñ Ð·Ð°Ð´Ð°Ñа), и ÑÑнкÑии-обÑабоÑÑики вÑполнÑÑÑÑÑ Ñже Ñ Ð½Ð¸Ð¼.
ÐобавлÑÐµÑ Ð¾Ð±ÑабоÑÑики в ÑпиÑки один меÑод: .then(onResolved, onRejected). ÐеÑод .catch(onRejected) â вÑего лиÑÑ ÑокÑаÑÑÐ½Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑ .then(null, onRejected).
Ðн Ð´ÐµÐ»Ð°ÐµÑ ÑледÑÑÑее:
- ÐÑли
PromiseState == "pending", Ñо еÑÑÑ Ð¿ÑÐ¾Ð¼Ð¸Ñ ÐµÑÑ Ð½Ðµ вÑполнен, Ñо обÑабоÑÑики добавлÑÑÑÑÑ Ð² ÑооÑвеÑÑÑвÑÑÑие ÑпиÑки. - ÐнаÑе обÑабоÑÑики ÑÑÐ°Ð·Ñ Ð¿Ð¾Ð¼ÐµÑаÑÑÑÑ Ð² оÑеÑÐµÐ´Ñ Ð½Ð° вÑполнение.
ÐдеÑÑ Ð²Ð°Ð¶Ð½Ð¾, ÑÑо обÑабоÑÑики можно добавлÑÑÑ Ð² лÑбой моменÑ. Ðожно до вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¿ÑомиÑа (они подождÑÑ), а можно â поÑле (вÑполнÑÑÑÑ Ð² ближайÑее вÑемÑ, ÑеÑез аÑÐ¸Ð½Ñ ÑоннÑÑ Ð¾ÑеÑедÑ).
ÐапÑимеÑ:
// ÐÑÐ¾Ð¼Ð¸Ñ Ð²ÑполниÑÑÑ ÑÑÐ°Ð·Ñ Ð¶Ðµ
var promise = new Promise((resolve, reject) => resolve(1));
// PromiseState = "resolved"
// PromiseResult = 1
// Ðобавили обÑабоÑÑик к вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð½Ð¾Ð¼Ñ Ð¿ÑомиÑÑ
promise.then(alert); // ...он ÑÑабоÑÐ°ÐµÑ ÑÑÑ Ð¶Ðµ
РазÑмееÑÑÑ, можно добавлÑÑÑ Ð¸ много обÑабоÑÑиков на один и ÑÐ¾Ñ Ð¶Ðµ пÑомиÑ:
// ÐÑÐ¾Ð¼Ð¸Ñ Ð²ÑполниÑÑÑ ÑÑÐ°Ð·Ñ Ð¶Ðµ
var promise = new Promise((resolve, reject) => resolve(1));
promise.then( function f1(result) {
alert(result); // 1
return 'f1';
})
promise.then( function f2(result) {
alert(result); // 1
return 'f2';
})
Ðид обÑекÑа promise поÑле ÑÑого:
Ðа ÑÑой иллÑÑÑÑаÑии можно ÑвидеÑÑ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð½Ñе нами обÑабоÑÑики f1, f2, а Ñакже â авÑомаÑиÑеÑки добавленнÑе обÑабоÑÑики оÑибок "Thrower".
Ðело в Ñом, ÑÑо .then, еÑли один из обÑабоÑÑиков не Ñказан, добавлÑÐµÑ ÐµÐ³Ð¾ Â«Ð¾Ñ ÑебÑ», ÑледÑÑÑим обÑазом:
- ÐÐ»Ñ ÑÑпеÑного вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ â ÑÑнкÑиÑ
Identity, коÑоÑÐ°Ñ Ð²ÑглÑÐ´Ð¸Ñ ÐºÐ°Ðºarg => arg, Ñо еÑÑÑ Ð²Ð¾Ð·Ð²ÑаÑÐ°ÐµÑ Ð°ÑгÑÐ¼ÐµÐ½Ñ Ð±ÐµÐ· изменений. - ÐÐ»Ñ Ð¾Ñибки â ÑÑнкÑиÑ
Thrower, коÑоÑÐ°Ñ Ð²ÑглÑÐ´Ð¸Ñ ÐºÐ°Ðºarg => throw arg, Ñо еÑÑÑ Ð³ÐµÐ½ÐµÑиÑÑÐµÑ Ð¾ÑибкÑ.
ÐÑо, по ÑÑÑи дела, ÑоÑмалÑноÑÑÑ, но без Ð½ÐµÑ Ð½ÐµÐºÐ¾ÑоÑÑе оÑобенноÑÑи Ð¿Ð¾Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¿ÑомиÑов могÑÑ Â«Ð½Ðµ ÑойÑиÑÑ» в обÑÑÑ Ð»Ð¾Ð³Ð¸ÐºÑ, поÑÑÐ¾Ð¼Ñ Ð¼Ñ Ñпоминаем о ней здеÑÑ.
ÐбÑаÑим внимание, в ÑÑом пÑимеÑе намеÑенно не иÑполÑзÑеÑÑÑ Ñейнинг. То еÑÑÑ, обÑабоÑÑики добавлÑÑÑÑÑ Ð¸Ð¼ÐµÐ½Ð½Ð¾ на один и ÑÐ¾Ñ Ð¶Ðµ пÑомиÑ.
ÐоÑÑÐ¾Ð¼Ñ Ð¾Ð±Ð° alert вÑдадÑÑ Ð¾Ð´Ð½Ð¾ знаÑение 1.
ÐÑе ÑÑнкÑии из ÑпиÑка обÑабоÑÑиков вÑзÑваÑÑÑÑ Ñ ÑезÑлÑÑаÑом пÑомиÑа, одна за дÑÑгой. Ðикакой пеÑедаÑи ÑезÑлÑÑаÑов Ð¼ÐµÐ¶Ð´Ñ Ð¾Ð±ÑабоÑÑиками в ÑамкаÑ
одного пÑомиÑа неÑ, а Ñам ÑезÑлÑÑÐ°Ñ Ð¿ÑомиÑа (PromiseResult) поÑле ÑÑÑановки не менÑеÑÑÑ.
ÐоÑÑомÑ, ÑÑÐ¾Ð±Ñ Ð¿ÑодолжиÑÑ ÑабоÑÑ Ñ ÑезÑлÑÑаÑом, иÑполÑзÑеÑÑÑ Ñейнинг.
ÐÐ»Ñ Ñого, ÑÑÐ¾Ð±Ñ ÑезÑлÑÑÐ°Ñ Ð¾Ð±ÑабоÑÑика пеÑедаÑÑ ÑледÑÑÑей ÑÑнкÑии, .then ÑоздаÑÑ Ð½Ð¾Ð²Ñй пÑÐ¾Ð¼Ð¸Ñ Ð¸ возвÑаÑÐ°ÐµÑ ÐµÐ³Ð¾.
РпÑимеÑе вÑÑе ÑоздаÑÑÑÑ Ð´Ð²Ð° ÑакиÑ
пÑомиÑа (Ñ.к. два вÑзова .then), каждÑй из коÑоÑÑÑ
даÑÑ ÑÐ²Ð¾Ñ Ð²ÐµÑÐºÑ Ð²ÑполнениÑ:
ÐзнаÑалÑно ÑÑи новÑе пÑомиÑÑ â «пÑÑÑÑе», они ждÑÑ. Ðогда в бÑдÑÑем вÑполнÑÑÑÑ Ð¾Ð±ÑабоÑÑики f1, f2, Ñо иÑ
ÑезÑлÑÑÐ°Ñ Ð±ÑÐ´ÐµÑ Ð¿ÐµÑедан в новÑе пÑомиÑÑ Ð¿Ð¾ ÑÑандаÑÑÐ½Ð¾Ð¼Ñ Ð¿ÑинÑипÑ:
- ÐÑли веÑнÑÑÑÑ Ð¾Ð±ÑÑное знаÑение (не пÑомиÑ), новÑй пÑÐ¾Ð¼Ð¸Ñ Ð¿ÐµÑейдÑÑ Ð²
"resolved"Ñ Ð½Ð¸Ð¼. - ÐÑли бÑл
throw, Ñо новÑй пÑÐ¾Ð¼Ð¸Ñ Ð¿ÐµÑейдÑÑ Ð² ÑоÑÑоÑние"rejected"Ñ Ð¾Ñибкой. - ÐÑли веÑнÑÑÑÑ Ð¿ÑомиÑ, Ñо иÑполÑзÑем его ÑезÑлÑÑÐ°Ñ (он Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÐºÐ°Ðº
resolved, Ñак иrejected).
ÐалÑÑе вÑполнÑÑÑÑ Ñже обÑабоÑÑики на новом пÑомиÑе, и Ñак далее.
ЧÑÐ¾Ð±Ñ Ð»ÑÑÑе понÑÑÑ Ð¿ÑоиÑÑ Ð¾Ð´ÑÑее, поÑмоÑÑим на ÑепоÑкÑ, коÑоÑÐ°Ñ Ð¿Ð¾Ð»ÑÑаеÑÑÑ Ð² пÑоÑеÑÑе напиÑÐ°Ð½Ð¸Ñ ÐºÐ¾Ð´Ð° Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ð° github-аваÑаÑа.
ÐеÑвÑй пÑÐ¾Ð¼Ð¸Ñ Ð¸ обÑабоÑка его ÑезÑлÑÑаÑа:
httpGet('/article/promise/user.json')
.then(JSON.parse)
ÐÑли пÑÐ¾Ð¼Ð¸Ñ Ð·Ð°Ð²ÐµÑÑилÑÑ ÑеÑез resolve, Ñо ÑезÑлÑÑÐ°Ñ â в JSON.parse, еÑли reject â Ñо в Thrower.
Ðак бÑло Ñказано вÑÑе, Thrower â ÑÑо ÑÑандаÑÑÐ½Ð°Ñ Ð²Ð½ÑÑÑеннÑÑ ÑÑнкÑиÑ, коÑоÑÐ°Ñ Ð°Ð²ÑомаÑиÑеÑки иÑполÑзÑеÑÑÑ, еÑли вÑоÑой обÑабоÑÑик не Ñказан.
Ðожно ÑÑиÑаÑÑ, ÑÑо вÑоÑой обÑабоÑÑик вÑглÑÐ´Ð¸Ñ Ñак:
httpGet('/article/promise/user.json')
.then(JSON.parse, err => throw err)
ÐамеÑим, ÑÑо когда обÑабоÑÑик в пÑомиÑаÑ
Ð´ÐµÐ»Ð°ÐµÑ throw â в данном ÑлÑÑае, пÑи оÑибке запÑоÑа, Ñо ÑÐ°ÐºÐ°Ñ Ð¾Ñибка не «валиÑ» ÑкÑÐ¸Ð¿Ñ Ð¸ не вÑводиÑÑÑ Ð² конÑоли. Ðна пÑоÑÑо бÑÐ´ÐµÑ Ð¿ÐµÑедана в ближайÑий ÑледÑÑÑий обÑабоÑÑик onRejected.
Ðобавим в код еÑÑ ÑÑÑокÑ:
httpGet('/article/promise/user.json')
.then(JSON.parse)
.then(user => httpGet(`https://api.github.com/users/${user.name}`))
ЦепоÑка «вÑÑоÑла вниз»:
ФÑнкÑÐ¸Ñ JSON.parse либо возвÑаÑÐ°ÐµÑ Ð¾Ð±ÑÐµÐºÑ Ñ Ð´Ð°Ð½Ð½Ñми, либо генеÑиÑÑÐµÑ Ð¾ÑÐ¸Ð±ÐºÑ (ÑÑо ÑаÑÑениваеÑÑÑ ÐºÐ°Ðº reject).
ÐÑли вÑÑ Ñ
оÑоÑо, Ñо then(user => httpGet(â¦)) веÑнÑÑ Ð½Ð¾Ð²Ñй пÑомиÑ, на коÑоÑÑй ÑÑоÑÑ Ñже два обÑабоÑÑика:
httpGet('/article/promise/user.json')
.then(JSON.parse)
.then(user => httpGet(`https://api.github.com/users/${user.name}`))
.then(
JSON.parse,
function avatarError(error) {
if (error.code == 404) {
return {name: "NoGithub", avatar_url: '/article/promise/anon.png'};
} else {
throw error;
}
}
})
ÐаконеÑ-Ñо Ñ Ð¾ÑÑ ÐºÐ°ÐºÐ°Ñ-Ñо обÑабоÑка оÑибок!
ÐбÑабоÑÑик avatarError пеÑеÑ
ваÑÐ¸Ñ Ð¾Ñибки, коÑоÑÑе бÑли Ñанее. ФÑнкÑÐ¸Ñ httpGet пÑи генеÑаÑии оÑибки запиÑÑÐ²Ð°ÐµÑ ÐµÑ HTTP-код в ÑвойÑÑво error.code, Ñак ÑÑо Ð¼Ñ Ð»ÐµÐ³ÐºÐ¾ можем понÑÑÑ â ÑÑо ÑÑо:
- ÐÑли ÑÑÑаниÑа на Github не найдена â можно пÑодолжиÑÑ Ð²Ñполнение, иÑполÑзÑÑ Â«Ð°Ð²Ð°ÑÐ°Ñ Ð¿Ð¾ ÑмолÑаниÑ»
- ÐнаÑе â пÑобÑаÑÑваем оÑÐ¸Ð±ÐºÑ Ð´Ð°Ð»ÑÑе.
ÐÑого, поÑле Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¾ÑÑавÑейÑÑ ÑаÑÑи ÑепоÑки, каÑÑина полÑÑаеÑÑÑ ÑледÑÑÑей:
'use strict';
httpGet('/article/promise/userNoGithub.json')
.then(JSON.parse)
.then(user => httpGet(`https://api.github.com/users/${user.name}`))
.then(
JSON.parse,
function githubError(error) {
if (error.code == 404) {
return {name: "NoGithub", avatar_url: '/article/promise/anon.png'};
} else {
throw error;
}
}
)
.then(function showAvatar(githubUser) {
let img = new Image();
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.appendChild(img);
setTimeout(() => img.remove(), 3000);
})
.catch(function genericError(error) {
alert(error); // Error: Not Found
});
РконÑе ÑÑабаÑÑÐ²Ð°ÐµÑ Ð¾Ð±Ñий обÑабоÑÑик genericError, коÑоÑÑй пеÑеÑ
ваÑÑÐ²Ð°ÐµÑ Ð»ÑбÑе оÑибки. Рданном ÑлÑÑае оÑибки, коÑоÑÑе в него попадÑÑ, Ñже ноÑÑÑ ÐºÑиÑиÑеÑкий Ñ
аÑакÑеÑ, ÑÑо-Ñо ÑеÑÑÑзно не Ñак. ЧÑÐ¾Ð±Ñ Ð¿Ð¾ÑеÑиÑÐµÐ»Ñ Ð½Ðµ ÑдивилÑÑ Ð¾ÑÑÑÑÑÑÐ²Ð¸Ñ Ð¸Ð½ÑоÑмаÑии, Ð¼Ñ Ð¿Ð¾ÐºÐ°Ð·Ñваем ÐµÐ¼Ñ ÑообÑение об ÑÑом.
Ðожно и как-Ñо инаÑе вÑвеÑÑи Ñведомление о пÑоблеме, главное â не забÑÑÑ Ð¾Ð±ÑабоÑаÑÑ Ð¾Ñибки в конÑе. ÐÑли поÑледнего catch не бÑдеÑ, а ÑепоÑка завеÑÑиÑÑÑ Ñ Ð¾Ñибкой, Ñо поÑеÑиÑÐµÐ»Ñ Ð¾Ð± ÑÑом не ÑзнаеÑ.
РконÑоли Ñоже ниÑего не бÑдеÑ, Ñак как оÑибка оÑÑаÑÑÑÑ Â«Ð²Ð½ÑÑÑи» пÑомиÑа, Ð¾Ð¶Ð¸Ð´Ð°Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÑледÑÑÑего обÑабоÑÑика onRejected, коÑоÑÐ¾Ð¼Ñ Ð±ÑÐ´ÐµÑ Ð¿ÐµÑедана.
ÐÑак, Ð¼Ñ ÑаÑÑмоÑÑели оÑновнÑе пÑиÑÐ¼Ñ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿ÑомиÑов. Ðалее â поÑмоÑÑим некоÑоÑÑе полезнÑе вÑпомогаÑелÑнÑе меÑодÑ.
ÐаÑаллелÑное вÑполнение
ЧÑо, еÑли Ð¼Ñ Ñ Ð¾Ñим оÑÑÑеÑÑвиÑÑ Ð½ÐµÑколÑко аÑÐ¸Ð½Ñ ÑоннÑÑ Ð¿ÑоÑеÑÑов одновÑеменно и обÑабоÑаÑÑ Ð¸Ñ ÑезÑлÑÑаÑ?
РклаÑÑе Promise еÑÑÑ ÑледÑÑÑие ÑÑаÑиÑеÑкие меÑодÑ.
Promise.all(iterable)
ÐÑзов Promise.all(iterable) полÑÑÐ°ÐµÑ Ð¼Ð°ÑÑив (или дÑÑгой иÑеÑиÑÑемÑй обÑекÑ) пÑомиÑов и возвÑаÑÐ°ÐµÑ Ð¿ÑомиÑ, коÑоÑÑй ждÑÑ, пока вÑе пеÑеданнÑе пÑомиÑÑ Ð·Ð°Ð²ÐµÑÑаÑÑÑ, и пеÑеÑ
Ð¾Ð´Ð¸Ñ Ð² ÑоÑÑоÑние «вÑполнено» Ñ Ð¼Ð°ÑÑивом иÑ
ÑезÑлÑÑаÑов.
ÐапÑимеÑ:
Promise.all([
httpGet('/article/promise/user.json'),
httpGet('/article/promise/guest.json')
]).then(results => {
alert(results);
});
ÐопÑÑÑим, Ñ Ð½Ð°Ñ ÐµÑÑÑ Ð¼Ð°ÑÑив Ñ URL.
let urls = [
'/article/promise/user.json',
'/article/promise/guest.json'
];
ЧÑÐ¾Ð±Ñ Ð·Ð°Ð³ÑÑзиÑÑ Ð¸Ñ Ð¿Ð°ÑаллелÑно, нÑжно:
- СоздаÑÑ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ URL ÑооÑвеÑÑÑвÑÑÑий пÑомиÑ.
- ÐбеÑнÑÑÑ Ð¼Ð°ÑÑив ÑакиÑ
пÑомиÑов в
Promise.all.
ÐолÑÑиÑÑÑ Ñак:
'use strict';
let urls = [
'/article/promise/user.json',
'/article/promise/guest.json'
];
Promise.all( urls.map(httpGet) )
.then(results => {
alert(results);
});
ÐамеÑим, ÑÑо еÑли какой-Ñо из пÑомиÑов завеÑÑилÑÑ Ñ Ð¾Ñибкой, Ñо ÑезÑлÑÑаÑом Promise.all бÑÐ´ÐµÑ ÑÑа оÑибка. ÐÑи ÑÑом оÑÑалÑнÑе пÑомиÑÑ Ð¸Ð³Ð½Ð¾ÑиÑÑÑÑÑÑ.
ÐапÑимеÑ:
Promise.all([
httpGet('/article/promise/user.json'),
httpGet('/article/promise/guest.json'),
httpGet('/article/promise/no-such-page.json') // (Ð½ÐµÑ Ñакой ÑÑÑаниÑÑ)
]).then(
result => alert("не ÑÑабоÑаеÑ"),
error => alert("ÐÑибка: " + error.message) // ÐÑибка: Not Found
)
Promise.race(iterable)
ÐÑзов Promise.race, как и Promise.all, полÑÑÐ°ÐµÑ Ð¸ÑеÑиÑÑемÑй обÑÐµÐºÑ Ñ Ð¿ÑомиÑами, коÑоÑÑе нÑжно вÑполниÑÑ, и возвÑаÑÐ°ÐµÑ Ð½Ð¾Ð²Ñй пÑомиÑ.
Ðо, в оÑлиÑие Ð¾Ñ Promise.all, ÑезÑлÑÑаÑом бÑÐ´ÐµÑ ÑолÑко пеÑвÑй ÑÑпеÑно вÑполнивÑийÑÑ Ð¿ÑÐ¾Ð¼Ð¸Ñ Ð¸Ð· ÑпиÑка. ÐÑÑалÑнÑе игноÑиÑÑÑÑÑÑ.
ÐапÑимеÑ:
Promise.race([
httpGet('/article/promise/user.json'),
httpGet('/article/promise/guest.json')
]).then(firstResult => {
firstResult = JSON.parse(firstResult);
alert( firstResult.name ); // iliakan или guest, ÑмоÑÑÑ ÑÑо загÑÑзиÑÑÑ ÑанÑÑе
});
Promise.resolve(value)
ÐÑзов Promise.resolve(value) ÑоздаÑÑ ÑÑпеÑно вÑполнивÑийÑÑ Ð¿ÑÐ¾Ð¼Ð¸Ñ Ñ ÑезÑлÑÑаÑом value.
Ðн аналогиÑен конÑÑÑÑкÑии:
new Promise((resolve) => resolve(value))
Promise.resolve иÑполÑзÑÑÑ, когда Ñ
оÑÑÑ Ð¿Ð¾ÑÑÑоиÑÑ Ð°ÑинÑ
ÑоннÑÑ ÑепоÑкÑ, и наÑалÑнÑй ÑезÑлÑÑÐ°Ñ Ñже еÑÑÑ.
ÐапÑимеÑ:
Promise.resolve(window.location) // наÑаÑÑ Ñ ÑÑого знаÑениÑ
.then(httpGet) // вÑзваÑÑ Ð´Ð»Ñ Ð½ÐµÐ³Ð¾ httpGet
.then(alert) // и вÑвеÑÑи ÑезÑлÑÑаÑ
Promise.reject(error)
ÐналогиÑно Promise.reject(error) ÑоздаÑÑ Ñже вÑполнивÑийÑÑ Ð¿ÑомиÑ, но не Ñ ÑÑпеÑнÑм ÑезÑлÑÑаÑом, а Ñ Ð¾Ñибкой error.
ÐапÑимеÑ:
Promise.reject(new Error("..."))
.catch(alert) // Error: ...
ÐеÑод Promise.reject иÑполÑзÑеÑÑÑ Ð¾ÑÐµÐ½Ñ Ñедко, гоÑаздо Ñеже Ñем resolve, поÑÐ¾Ð¼Ñ ÑÑо оÑибка Ð²Ð¾Ð·Ð½Ð¸ÐºÐ°ÐµÑ Ð¾Ð±ÑÑно не в наÑале ÑепоÑки, а в пÑоÑеÑÑе ÐµÑ Ð²ÑполнениÑ.
ÐÑого
- ÐÑÐ¾Ð¼Ð¸Ñ â ÑÑо ÑпеÑиалÑнÑй обÑекÑ, коÑоÑÑй Ñ ÑÐ°Ð½Ð¸Ñ ÑÐ²Ð¾Ñ ÑоÑÑоÑние, ÑекÑÑий ÑезÑлÑÑÐ°Ñ (еÑли еÑÑÑ) и колбÑки.
- ÐÑи Ñоздании
new Promise((resolve, reject) => ...)авÑомаÑиÑеÑки запÑÑкаеÑÑÑ ÑÑнкÑиÑ-аÑгÑменÑ, коÑоÑÐ°Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° вÑзваÑÑresolve(result)пÑи ÑÑпеÑном вÑполнении иreject(error)â пÑи оÑибке. - ÐÑгÑменÑ
resolve/reject(ÑолÑко пеÑвÑй, оÑÑалÑнÑе игноÑиÑÑÑÑÑÑ) пеÑедаÑÑÑÑ Ð¾Ð±ÑабоÑÑикам на ÑÑом пÑомиÑе. - ÐбÑабоÑÑики назнаÑаÑÑÑÑ Ð²Ñзовом
.then/catch. - ÐÐ»Ñ Ð¿ÐµÑедаÑи ÑезÑлÑÑаÑа Ð¾Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ обÑабоÑÑика к дÑÑÐ³Ð¾Ð¼Ñ Ð¸ÑполÑзÑеÑÑÑ Ñейнинг.
У пÑомиÑов еÑÑÑ Ð½ÐµÐºÐ¾ÑоÑÑе огÑаниÑениÑ. Ð ÑаÑÑноÑÑи, ÑÑандаÑÑ Ð½Ðµ пÑедÑÑмаÑÑÐ¸Ð²Ð°ÐµÑ ÐºÐ°ÐºÐ¾Ð¹-Ñо меÑод Ð´Ð»Ñ Â«Ð¾ÑменÑ» пÑомиÑа, Ñ Ð¾ÑÑ Ð² ÑÑде ÑиÑÑаÑий (http-запÑоÑÑ) ÑÑо бÑло Ð±Ñ Ð´Ð¾Ð²Ð¾Ð»Ñно Ñдобно. Ðозможно, он поÑвиÑÑÑ Ð² ÑледÑÑÑей веÑÑии ÑÑандаÑÑа JavaScript.
Ð ÑовÑеменной JavaScript-ÑазÑабоÑке ÑложнÑе ÑепоÑки Ñ Ð¿ÑомиÑами иÑполÑзÑÑÑÑÑ Ñедко, Ñак как они кÑда пÑоÑе опиÑÑваÑÑÑÑ Ð¿Ñи помоÑи генеÑаÑоÑов Ñ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñекой co, коÑоÑÑе ÑаÑÑмоÑÑÐµÐ½Ñ Ð² ÑооÑвеÑÑÑвÑÑÑей главе. Ðожно ÑказаÑÑ, ÑÑо пÑомиÑÑ Ð»ÐµÐ¶Ð°Ñ Ð² оÑнове более пÑодвинÑÑÑÑ
ÑпоÑобов аÑинÑ
Ñонной ÑазÑабоÑки.
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)