ÐбÑабоÑÑики пÑомиÑов .then/.catch/.finally вÑегда аÑинÑ
ÑоннÑ.
Ðаже когда пÑÐ¾Ð¼Ð¸Ñ ÑÑÐ°Ð·Ñ Ð¶Ðµ вÑполнен, код в ÑÑÑокаÑ
ниже .then/.catch/.finally бÑÐ´ÐµÑ Ð·Ð°Ð¿ÑÑен до ÑÑиÑ
обÑабоÑÑиков.
ÐÐ¾Ñ Ð´ÐµÐ¼Ð¾:
let promise = Promise.resolve();
promise.then(() => alert("пÑÐ¾Ð¼Ð¸Ñ Ð²Ñполнен"));
alert("код вÑполнен"); // ÑÑÐ¾Ñ alert показÑваеÑÑÑ Ð¿ÐµÑвÑм
ÐÑли Ð²Ñ Ð·Ð°Ð¿ÑÑÑиÑе его, ÑнаÑала Ð²Ñ ÑвидиÑе код вÑполнен, а поÑом пÑÐ¾Ð¼Ð¸Ñ Ð²Ñполнен.
ÐÑо ÑÑÑанно, поÑÐ¾Ð¼Ñ ÑÑо пÑÐ¾Ð¼Ð¸Ñ Ð¾Ð¿ÑеделÑнно бÑл вÑполнен Ñ Ñамого наÑала.
ÐоÑÐµÐ¼Ñ .then ÑÑабаÑÑÐ²Ð°ÐµÑ Ð¿Ð¾Ð·Ð¶Ðµ? ЧÑо пÑоиÑÑ
одиÑ?
ÐÑеÑÐµÐ´Ñ Ð¼Ð¸ÐºÑозадаÑ
ÐÑинÑ
ÑоннÑе задаÑи ÑÑебÑÑÑ Ð¿ÑавилÑного ÑпÑавлениÑ. ÐÐ»Ñ ÑÑого ÑÑандаÑÑ Ð¿ÑедÑÑмаÑÑÐ¸Ð²Ð°ÐµÑ Ð²Ð½ÑÑÑеннÑÑ Ð¾ÑеÑÐµÐ´Ñ PromiseJobs, более извеÑÑнÑÑ ÐºÐ°Ðº «оÑеÑÐµÐ´Ñ Ð¼Ð¸ÐºÑÐ¾Ð·Ð°Ð´Ð°Ñ (microtask queue)» (ÑеÑмин V8).
Ðак Ñказано в ÑпеÑиÑикаÑии:
- ÐÑеÑÐµÐ´Ñ Ð¾Ð¿ÑеделÑеÑÑÑ ÐºÐ°Ðº пеÑвÑм-пÑиÑÑл-пеÑвÑм-ÑÑÑл (FIFO): задаÑи, попавÑие в оÑеÑÐµÐ´Ñ Ð¿ÐµÑвÑми, вÑполнÑÑÑÑÑ Ñоже пеÑвÑми.
- ÐÑполнение задаÑи пÑоиÑÑ Ð¾Ð´Ð¸Ñ ÑолÑко в Ñом ÑлÑÑае, еÑли ниÑего болÑÑе не запÑÑено.
Ðли, пÑоÑе говоÑÑ, когда пÑÐ¾Ð¼Ð¸Ñ Ð²Ñполнен, его обÑабоÑÑики .then/catch/finally попадаÑÑ Ð² оÑеÑедÑ. Ðни пока не вÑполнÑÑÑÑÑ. Ðвижок JavaScript беÑÑÑ Ð·Ð°Ð´Ð°ÑÑ Ð¸Ð· оÑеÑеди и вÑполнÑÐµÑ ÐµÑ, когда он оÑвободиÑÑÑ Ð¾Ñ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÑекÑÑего кода.
ÐÐ¾Ñ Ð¿Ð¾ÑÐµÐ¼Ñ ÑообÑение «код вÑполнен» в пÑимеÑе вÑÑе бÑÐ´ÐµÑ Ð¿Ð¾ÐºÐ°Ð·Ð°Ð½Ð¾ пеÑвÑм.
ÐбÑабоÑÑики пÑомиÑов вÑегда пÑÐ¾Ñ Ð¾Ð´ÑÑ ÑеÑез ÑÑÑ Ð²Ð½ÑÑÑеннÑÑ Ð¾ÑеÑедÑ.
ÐÑли еÑÑÑ ÑепоÑка Ñ Ð½ÐµÑколÑкими .then/catch/finally, Ñо каждÑй из ниÑ
вÑполнÑеÑÑÑ Ð°ÑинÑ
Ñонно. То еÑÑÑ ÑнаÑала ÑÑавиÑÑÑ Ð² оÑеÑедÑ, а поÑом вÑполнÑеÑÑÑ, когда вÑполнение ÑекÑÑего кода завеÑÑено и добавленнÑе Ñанее в оÑеÑÐµÐ´Ñ Ð¾Ð±ÑабоÑÑики вÑполненÑ.
Ðо ÑÑо еÑли поÑÑдок Ð¸Ð¼ÐµÐµÑ Ð·Ð½Ð°Ñение Ð´Ð»Ñ Ð½Ð°Ñ? Ðак Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ вÑвеÑÑи код вÑполнен поÑле пÑÐ¾Ð¼Ð¸Ñ Ð²Ñполнен?
Ðегко, иÑполÑзÑÑ .then:
Promise.resolve()
.then(() => alert("пÑÐ¾Ð¼Ð¸Ñ Ð²Ñполнен!"))
.then(() => alert("код вÑполнен"));
ТепеÑÑ Ð¿Ð¾ÑÑдок ÑÑал Ñаким, как бÑло задÑмано.
ÐеобÑабоÑаннÑе оÑибки
ÐомниÑе «необÑабоÑаннÑе оÑибки» из Ð³Ð»Ð°Ð²Ñ ÐÑомиÑÑ: обÑабоÑка оÑибок?
ТепеÑÑ Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ опиÑаÑÑ, как именно JavaScript понимаеÑ, ÑÑо оÑибка не обÑабоÑана.
«ÐеобÑабоÑÐ°Ð½Ð½Ð°Ñ Ð¾Ñибка» Ð²Ð¾Ð·Ð½Ð¸ÐºÐ°ÐµÑ Ð² ÑлÑÑае, еÑли оÑибка пÑомиÑа не обÑабаÑÑваеÑÑÑ Ð² конÑе оÑеÑеди микÑозадаÑ.
ÐбÑÑно, еÑли Ð¼Ñ Ð¾Ð¶Ð¸Ð´Ð°ÐµÐ¼ оÑибкÑ, Ð¼Ñ Ð´Ð¾Ð±Ð°Ð²Ð»Ñем .catch в ÐºÐ¾Ð½ÐµÑ ÑепоÑки пÑомиÑов, ÑÑÐ¾Ð±Ñ Ð¾Ð±ÑабоÑаÑÑ ÐµÑ:
let promise = Promise.reject(new Error("ÐÑибка в пÑомиÑе!"));
promise.catch(err => alert('поймана!'));
// не запÑÑÑиÑÑÑ, оÑибка обÑабоÑана
window.addEventListener('unhandledrejection', event => {
alert(event.reason);
});
â¦Ðо еÑли Ð¼Ñ Ð·Ð°Ð±Ñдем добавиÑÑ .catch, Ñо, когда оÑеÑÐµÐ´Ñ Ð¼Ð¸ÐºÑÐ¾Ð·Ð°Ð´Ð°Ñ Ð¾Ð¿ÑÑÑееÑ, движок ÑгенеÑиÑÑÐµÑ ÑобÑÑие:
let promise = Promise.reject(new Error("ÐÑибка в пÑомиÑе!"));
// ÐÑибка в пÑомиÑе!
window.addEventListener('unhandledrejection', event => alert(event.reason));
Ð ÑÑо, еÑли Ð¼Ñ Ð¿Ð¾Ð¹Ð¼Ð°ÐµÐ¼ оÑибкÑ, но позже? ÐÐ¾Ñ Ñак:
let promise = Promise.reject(new Error("ÐÑибка в пÑомиÑе!"));
setTimeout(() => promise.catch(err => alert('поймана')), 1000);
// ÐÑибка в пÑомиÑе!
window.addEventListener('unhandledrejection', event => alert(event.reason));
ТепеÑÑ, пÑи запÑÑке, Ð¼Ñ ÑнаÑала Ñвидим «ÐÑибка в пÑомиÑе!», а заÑем «поймана».
ÐÑли Ð±Ñ Ð¼Ñ Ð½Ðµ знали пÑо оÑеÑÐµÐ´Ñ Ð¼Ð¸ÐºÑозадаÑ, Ñо могли Ð±Ñ ÑдивиÑÑÑÑ: «ÐоÑÐµÐ¼Ñ ÑÑабоÑал обÑабоÑÑик unhandledrejection? ÐÑ Ð¶Ðµ поймали оÑибкÑ!».
Ðо ÑепеÑÑ Ð¼Ñ Ð¿Ð¾Ð½Ð¸Ð¼Ð°ÐµÐ¼, ÑÑо ÑобÑÑие unhandledrejection возникаеÑ, когда оÑеÑÐµÐ´Ñ Ð¼Ð¸ÐºÑÐ¾Ð·Ð°Ð´Ð°Ñ Ð·Ð°Ð²ÐµÑÑена: движок пÑовеÑÑÐµÑ Ð²Ñе пÑомиÑÑ Ð¸, еÑли какой-либо из ниÑ
в ÑоÑÑоÑнии «rejected», Ñо генеÑиÑÑеÑÑÑ ÑÑо ÑобÑÑие.
РпÑимеÑе вÑÑе .catch, добавленнÑй в setTimeout, Ñакже ÑÑабаÑÑваеÑ, но позже, Ñже поÑле Ð²Ð¾Ð·Ð½Ð¸ÐºÐ½Ð¾Ð²ÐµÐ½Ð¸Ñ unhandledrejection, Ñак ÑÑо ÑÑо ни на ÑÑо не влиÑеÑ.
ÐÑого
ÐбÑабоÑка пÑомиÑов вÑегда аÑÐ¸Ð½Ñ ÑоннаÑ, Ñ.к. вÑе дейÑÑÐ²Ð¸Ñ Ð¿ÑомиÑов пÑÐ¾Ñ Ð¾Ð´ÑÑ ÑеÑез внÑÑÑеннÑÑ Ð¾ÑеÑÐµÐ´Ñ Â«promise jobs», Ñак назÑваемÑÑ Â«Ð¾ÑеÑÐµÐ´Ñ Ð¼Ð¸ÐºÑÐ¾Ð·Ð°Ð´Ð°Ñ (microtask queue)» (ÑеÑмин V8).
Таким обÑазом, обÑабоÑÑики .then/catch/finally вÑзÑваÑÑÑÑ Ð¿Ð¾Ñле вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÑекÑÑего кода.
ÐÑли нам нÑжно гаÑанÑиÑоваÑÑ Ð²Ñполнение какого-Ñо кода поÑле .then/catch/finally, Ñо лÑÑÑе вÑего добавиÑÑ ÐµÐ³Ð¾ вÑзов в ÑепоÑÐºÑ .then.
РболÑÑинÑÑве движков JavaScript, вклÑÑÐ°Ñ Ð±ÑаÑзеÑÑ Ð¸ Node.js, микÑозадаÑи ÑеÑно ÑвÑÐ·Ð°Ð½Ñ Ñ Ñак назÑваемÑм «ÑобÑÑийнÑм Ñиклом» и «макÑозадаÑами». Так как они не ÑвÑÐ·Ð°Ð½Ñ Ð½Ð°Ð¿ÑÑмÑÑ Ñ Ð¿ÑомиÑами, Ñо ÑаÑÑмаÑÑиваÑÑÑÑ Ð² дÑÑгой ÑаÑÑи ÑÑебника, в главе СобÑÑийнÑй Ñикл: микÑозадаÑи и макÑозадаÑи.
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)