Promisifikatsiya
Promisifikatsiya โ callback qabul qiluvchi funksiyani promise qaytaradigan funksiyaga aylantirish uchun ishlatiladigan uzun so'z. Ko'p funksiyalar va kutubxonalar callback'ga asoslangan, lekin promise'lar bilan ishlash qulayroq โ shuning uchun ularni promise'ga o'girish foydali.
Callback uslubidagi funksiya
Aytaylik, bizda skript yuklovchi callback uslubidagi funksiya bor. U callback(error, result) ko'rinishidagi callback qabul qiladi โ bu "error-first callback" deb ataladigan keng tarqalgan uslub:
function loadScript(src, callback) {
let script = document.createElement('script');
script.src = src;
script.onload = () => callback(null, script);
script.onerror = () => callback(new Error('Skript yuklanmadi: ' + src));
document.head.append(script);
}
// Ishlatilishi:
// loadScript('path/script.js', (err, script) => {...})
Endi biz uni promise qaytaradigan versiyaga aylantiramiz โ ya'ni promisifikatsiya qilamiz.
Qo'lda promisifikatsiya
Yangi funksiya loadScriptPromise(src) callback o'rniga promise qaytaradi. Uning ichida eski loadScript chaqiriladi va callback promise'ni resolve/reject qiladi:
let loadScriptPromise = function(src) {
return new Promise((resolve, reject) => {
loadScript(src, (err, script) => {
if (err) reject(err);
else resolve(script);
});
});
};
// Endi promise sifatida ishlatamiz:
loadScriptPromise('path/script.js')
.then(script => console.log('Yuklandi: ' + script.src))
.catch(err => console.log('Xato: ' + err.message));
Ko'rib turibmiz: yangi funksiya eski funksiyaning ishini bajaradi, lekin callback o'rniga promise qaytaradi. Xato bo'lsa promise reject bo'ladi, aks holda natija bilan resolve bo'ladi.
loadScriptPromise callback qabul qilmaydi. Barcha ish promise ichida bo'ladi, va biz .then/.catch orqali natijani olamiz.Umumiy promisify yordamchisi
Amalda bizga bitta emas, bir nechta funksiyani promisifikatsiya qilish kerak bo'ladi. Har safar qo'lda yozish o'rniga, umumiy promisify yordamchi funksiyasini yozish qulayroq.
Bu yordamchi "error-first callback" uslubidagi istalgan funksiyani qabul qilib, promise qaytaradigan yangi funksiyani beradi:
function promisify(f) {
return function(...args) { // o'ralgan (wrapper) funksiya qaytadi
return new Promise((resolve, reject) => {
// f uchun maxsus callback yaratamiz
function callback(err, result) {
if (err) {
reject(err);
} else {
resolve(result);
}
}
args.push(callback); // argumentlar oxiriga callback qo'shamiz
f.call(this, ...args); // asl funksiyani chaqiramiz
});
};
}
// Ishlatilishi:
let loadScriptPromise = promisify(loadScript);
loadScriptPromise('path/script.js').then(/*...*/);
Bu qanday ishlaydi:
promisify(f)yangi wrapper funksiya qaytaradi;- Wrapper chaqirilganda yangi promise yaratiladi;
- Wrapper asl
ffunksiyasini chaqiradi va uning argumentlariga maxsuscallbackqo'shadi; - Callback ishga tushganda: xato bo'lsa
reject, aks holdaresolveqiladi.
Bir nechta natijali callback
Yuqoridagi promisify callback'ning faqat bitta natijasini (result) oladi. Ammo ba'zi funksiyalar callback'ga bir nechta argument beradi: callback(err, res1, res2, ...). Ular uchun promisify'ni kengaytiramiz:
// promisify(f, true) โ natijalar massivini olish uchun
function promisify(f, manyArgs = false) {
return function(...args) {
return new Promise((resolve, reject) => {
function callback(err, ...results) { // f uchun callback
if (err) {
reject(err);
} else {
// manyArgs true bo'lsa, butun results massivini resolve qilamiz
resolve(manyArgs ? results : results[0]);
}
}
args.push(callback);
f.call(this, ...args);
});
};
}
// Ishlatilishi:
let f = promisify(f, true);
f(...).then(arrayOfResults => /*...*/, err => /*...*/);
util.promisify tayyor yordamchi funksiyasi bor. Amalda ko'pincha o'z qo'lida yozish o'rniga shundan foydalaniladi.Cheklovlar
Shu sababli, bir necha marta chaqiriladigan callback'lar (masalan, hodisa tinglovchilari) uchun promisifikatsiya mos kelmaydi.
Xulosa
- Promisifikatsiya โ callback uslubidagi funksiyani promise qaytaradigan funksiyaga aylantirish;
- U kodni
.then/.catchyokiasync/awaitbilan qulay ishlatishga imkon beradi; - Umumiy
promisifyyordamchisi "error-first callback" funksiyalarni avtomatik o'giradi; - Node.js'da tayyor
util.promisifymavjud; - Faqat bir marta chaqiriladigan callback'lar uchun mos keladi.