JavaScript Promise

5 хв. читання

JavaScript Promise - результат операції, яка ще не завершена, але буде в якийсь невизначений момент в майбутньому. Прикладом такої операції є мережевий запит. Коли ми витягуємо дані з деякого джерела, наприклад з API, для нас немає ніякого способу абсолютно визначити, коли буде отримано відповідь.

Це може бути проблематичним, якщо у нас є інші операції, що залежать від завершення цього мережевого запиту. Без Promises, ми повинні використовувати зворотні виклики для визначення дій, які повинні відбутися в певній послідовності. Це не обов'язково стане проблемою, якщо ми маємо тільки одну асинхронну дію. Але якщо нам потрібно завершити декілька асинхронних дій послідовно, зворотні виклики стають некерованими і призведуть до сумнозвісного callback hell.

doSomething(function(responseOne) {
doSomethingElse(responseOne, function(responseTwo, err) {
if (err) { handleError(err); }
doMoreStuff(responseTwo, function(responseThree, err) {
if (err) { handleAnotherError(err); }
doFinalThing(responseThree, function(err) {
if (err) { handleAnotherError(err); }
// Complete
}); // end doFinalThing
}); // end doMoreStuff
}); // end doSomethingElse
}); // end doSomething 

Promises забезпечують стандартизований і чистий метод визначення задач, які потрібно реалізувати в певній послідовності.

doSomething()
.then(doSomethingElse)
.catch(handleError)
.then(doMoreStuff)
.then(doFinalThing)
.catch(handleAnotherError) 

Створення Promises

Promise створюється за допомогою Promise конструктору. Приймається функція з двома аргументи (resolve, reject) в якості єдиного параметра.

var promise = new Promise( function(resolve, reject) { /* Promise content */ } 

enter image description here {full-post-img}

В середині функції ми можемо виконати будь-які асинхронні задачі, які ми хочемо. Для позначення Promise як виконана, ми викликаємо resolve(), необов'язково передаючи значення яке ми хочемо повернути. Для позначення Promise як відхилена або провалена, ми викликаємо reject(), при цьому необов'язково передаючи повідомлення про помилку. Перед тим, як Promise виконана або відхилена, вона знаходиться в стані очікування.

Ось загальна Promise-ified версія XMLHttpRequest:

/* CREDIT - Jake Archibald, http://www.html5rocks.com/en/tutorials/es6/promises/ */
function get(url) {
return new Promise(function(resolve, reject) {

var req = new XMLHttpRequest();
req.open('GET', url);

req.onload = function() {
if (req.status == 200) {
resolve(req.response); /* PROMISE RESOLVED */
} else {
reject(Error(req.statusText)); /* PROMISE REJECTED */
}
};

req.onerror = function() { reject(Error("Network Error")); };
req.send();
});
}

Використання Promises

Після того, як ми створили Promise, ми повинні реально використовувати її. Для виконання promise-ified функції, ми можемо викликати її як і будь-яку звичайну функцію. Але, оскільки це promise, ми тепер маємо доступ до методу .then (), який ми можемо додати до функції і який буде виконаний, коли promise більше не знаходиться на розгляді.

Метод .then () приймає два необов'язкові параметри. По-перше, функція викликається, якщо promise виконано. По-друге, функція викликається, якщо promise буде відхилено.

get(url)
.then(function(response) {
/* successFunction */
}, function(err) {
/* errorFunction */
})

enter image description here {full-post-img}

Обробка помилок

Оскільки обидві, успішна і помилкова, функції є необов'язковими, ми можемо розділити їх на дві .then () для кращого читання.

get(url)
.then(function(response) {
/* successFunction */
}, undefined)
.then(undefined, function(err) {
/* errorFunction */
})

Щоб зробити речі ще більш зручними для читання, ми використовуємо метод .catch(), який є скороченням для .then(undefined, errorFunction).

get(url)
.then(function(response) {
/* successFunction */
})
.catch(function(err) {
/* errorFunction */
})

enter image description here {full-post-img}

Формування послідовності

Реальне значення в промісах, коли ми маємо декілька асинхронних функцій які нам потрібно виконати в певному порядку. Ми можемо зв'язати .then() і .catch() разом, щоб створити послідовність асинхронних функцій.

Ми робимо це, повертаючи іншу promise в межах успішної чи помилкової функції. Наприклад -

get(url)
.then(function(response) {
response = JSON.parse(response);
var secondURL = response.data.url
return get( secondURL ); /* Return another Promise */
})
.then(function(response) {
response = JSON.parse(response);
var thirdURL = response.data.url 
return get( thirdURL ); /* Return another Promise */
})
.catch(function(err) {
handleError(err);
});

Якщо promise з ланцюжка вирішена, вона буде рухатися далі до наступної успішної функції (.then() ) в послідовності. Якщо, з іншого боку, promise відхилена, вона перейде до наступної помилкової функція (.catch()) в послідовності.

enter link description here

Асинхронне виконання promises

Можуть бути випадки, коли ми хочемо виконати групу promise-ified функцій асинхронно, і потів виконати дію тільки тоді, коли всі promises будуть завершені. Наприклад, якщо ми хочемо перенести декілька зображень і відображати їх на сторінці.

Для цього нам потрібно використати два методи. Перший - метод Array.map() дозволяє нам виконати дію для кожного елемента масиву, і створює новий масив результатів цих дій.

Другий - метод Promise.all() повертає promise, який виконано тільки тоді коли всі проміси з масиву будуть вирішені. Якщо який-небудь один promise в межах масиву відхиляється, Promise.all () promise також відхиляється.

var arrayOfURLs = ['one.json', 'two.json', 'three.json', 'four.json'];
var arrayOfPromises = arrayOfURLs.map(get);

Promise.all(arrayOfPromises)
.then(function(arrayOfResults) {
/* Do something when all Promises are resolved */
})
.catch(function(err) {
/* Handle error is any of Promises fails */
})

enter image description here {full-post-img}

Якщо ми подивимося на панелі Network в наших інструментах розробки, ми можемо бачити, що всі вибрані запити відбуваються паралельно.

enter image description here {full-post-img}

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.8K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація