Промис - это объект который дает тебе описать как работать с данными которые еще не появились программе.
Например у тебя есть магазин. Фронтенде ты показываешь количество продуктов. Пусть это значение получается асинхронно (может 1 или несколько запросов). Тогда чтобы описать получение количества продуктов ты пишешь код вида, где возвращаешь Promise
. В момент возврата промис еще не зарезолвлен (не resolved), нет значения прикрепленного к нему. Зато у него есть методы .then
, .catch
через которые потребиталь может описать функции которые выполнятся когда в промисе появится значение (устанавливается с помощью вызова resolve
).
function getProductsCount() {
return new Promise(function (resolve, reject) {
//...
//...
})
}
А потребитель количества продуктов описать что он будет делать когда значение вычислится (когда промис зарезолвится). Именно эту мезанику я имею в виду когда говорю “объект который дает тебе описать как работать с данными которые еще не появились программе”.
getProductsCount().then(function (productCount) {
$('.product-count').text(productCount)
})
Использование в ajax-е - не единственное место для промисов. Они нужны почти в любом асинхронном API: например на сервере промисы ипользуются для описания результатов вызовов базы данных, файловой системы. С помощью промисов удобно моделировать множественные запросы в виде одного промиса: это когда нужно сделать 5-10 запросов на сервер и работать с результатом всех запросов.
Разные задачи, но не взаимоисключающие. Ситуация именно такая как выглядит: с помощью catch
ты описываешь только обработчик для ошибки. С помощью then
ты описываешь обработчик для успеха а так же можешь описать обработчик для ошибки.
Ты всегда передаешь функции в promise чтобы он их контролировал. Воспро оборачивания не стоит, обращай внимание где функции передаются аргументами.
Ты передаешь функцию в промис, он контролирует когда ее вызвать. При ее вызове он контролирует какие функции передать в аргументы вызванной функции. Эти функции будут в переменных resolve
, reject
и уже ты определяешь когда их вызывать. Их вызов даст сигнал промису что или значение получено или ошибка
const p = new Promise(function (resolve, reject) {
//....
})
И при использовании промиса через его методы ты тоже даешь функцию чтобы ее контролировал промис:
p.then(function (res) {
console.log(res)
})
var isNetworkOK = true;
function downloadFile(url) { // Обязательно оборачивать в функцию Promise? Что это даёт?
// это дает возможность получить сколько угодно промисов, параметрезировав запрос по url.
// если не использовать функции то ты опишешь промис для 1 конкретного урла.
// с функцией ты можешь описать получение промисов для разных урлов (соответственно загрузку любого файла по урлу)
console.log("Start downloading file ..."); // ***
// A Promise
var willIGetAFile = new Promise (
function (resolve, reject) {
if (isNetworkOK) {
setTimeout( function() {
console.log("Complete the download process!"); // ***
var file = {
fileName: 'file.mp3',
fileContent: '...',
fileSize: '3 MB'
};
resolve(file); // resolve всегда должен возвращать объект?
// нет. Это может быть примитив: число, boolean итд.
}, 5 * 1000);
} else {
var error = new Error('There is a problem with the network.');
reject(error);
}
}
);
return willIGetAFile; // Зачем возвращать Promise? Разве он не был возвращён на 18 строке? ( resolve(file) )
// забудь на секунду про промисы и посмотри на синтаксические конструкции как на функции и объекты
// в какой строке функция downloadFile возвращает значение? (подсказка - не в 18).
// теперь можешь вспомнить про промисы: return нужен чтобы результат работы функции был тем что справа от `return` - объект
// которым ниже потребитель будет пользоваться чтобы описать что делать с результатом.
// в18 строке устанавлиается значение промиса, это не тоже самое что вернуть объект промиса
}
// те же вопросы касаются и функции ниже
// те же ответы
function openFile(file) {
console.log("Start opening file ..."); // ***
var willFileOpen = new Promise(
function (resolve, reject) {
var message = "File " + file.fileName + " opened!"
resolve(message);
}
);
return willFileOpen;
}
console.log("Start app.."); // ***
// Call downloadFile(..) function:
// Returns a Promise object:
var willIGetAFile = downloadFile("http://example.com/file.mp3"); // Что здесь происходит? Мы что, перетираем промис на 7 строчке?
// мы записываем в willIGetAFile инстанс промиса (это у которого методы then и catch)
// этот объект представляет "обещаение" данных, и мы можем описать что мы хотим делать с данными если/когда они появятся.
willIGetAFile // Здесь уже находится не промис, а downloadFile("http://example.com/file.mp3") И у него вызывается then... Почему?
// Здесь уже находится не промис, а downloadFile("http://example.com/file.mp3") - в чем разница?
// promise - это значение (вернее тип значения), downloadFile("http://example.com/file.mp3") - результат вызова функции, значение, значение типа промис. Тут нет противоречия
.then(openFile) // Chain it!
.then(function (fulfilled) { // If successful fileOpen.
// Get a message after file opened!
// Output: File file.mp3 opened!
console.log(fulfilled);
})
.catch(function (error) {
// Network Error!
// Output: There is a problem with the network.
console.log(error.message);
});
console.log("End app.."); // ***