Promisifikatsiya â oddiy oâzgarish uchun uzun soâz. Qayta chaqiruvni qabul qiladigan funktsiyani vaâda beradigan funktsiyaga aylantirish.
Boshqacha qilib aytganda, biz xuddi shu narsani bajaradigan, asl nusxasini ichki sifatida chaqiradigan, lekin vaâda qaytaradigan funktsiyani yaratamiz.
Bunday oâzgartirishlar koâpincha hayotda kerak boâladi, chunki koâplab funktsiyalar va kutubxonalar qayta chaqiruvga asoslangan. Ammo vaâdalar yanada qulayroq. Shunday qilib, ularni vaâda qilish mantiqan.
Masalan, bizda Kirish: callbacklar boâlimidan loadScript(src, callback) mavjud.
function loadScript(src, callback) {
let script = document.createElement("script");
script.src = src;
script.onload = () => callback(null, script);
script.onerror = () => callback(new Error(`Script load error for ${src}`));
document.head.append(script);
}
// usage:
// loadScript('path/script.js', (err, script) => {...})
Keling, buni vaâda qilaylik. Yangi loadScriptPromise(src) funktsiyasi ham xuddi shunday qiladi, lekin faqat src ni qabul qiladi (qayta chaqiruv qilinmaydi) va vaâda qaytaradi.
Letâs promisify it.
Weâll make a new function loadScriptPromise(src), that does the same (loads the script), but returns a promise instead of using callbacks.
In other words, we pass it only src (no callback) and get a promise in return, that resolves with script when the load is successful, and rejects with the error otherwise.
Here it is:
let loadScriptPromise = function (src) {
return new Promise((resolve, reject) => {
loadScript(src, (err, script) => {
if (err) reject(err);
else resolve(script);
});
});
};
// usage:
// loadScriptPromise('path/script.js').then(...)
Endi loadScriptPromise bizning vaâdamizga asoslangan kodga mos keladi.
Koârib turganimizdek, u barcha ishni asl loadScript â ga topshiradi va resolve/reject vaâdasini tarjima qiladigan oâz chaqiruvini qaytaradi.
Koâp funktsiyalarni vaâda qilishimiz kerak boâlishi mumkinligi sababli, yordamchidan foydalanish mantiqan toâgâri keladi.
Bu aslida juda oddiy â promisify(f) quyida vaâda berish uchun f funktsiyasini oladi va oârash funktsiyasini qaytaradi.
Ushbu oâram yuqoridagi kodda boâlgani kabi ishlaydi: vaâdani qaytaradi va chaqiruvni asl holatiga qaytaradi, natijada maxsus qayta chaqiruv natijasini kuzatadi:
function promisify(f) {
return function (...args) { // o'ram funktsiyasini qaytaradi
return new Promise((resolve, reject) => {
function callback(err, result) { //
if (err) {
reject(err);
} else {
resolve(result);
}
}
args.push(callback); // argumentlar oxiriga qadar bizning maxsus qayta chaqiruvni qo'shing
f.call(this, ...args); // asl funktsiyani chaqiring
});
};
}
// Foydalanish:
let loadScriptPromise = promisify(loadScript);
loadScriptPromise(...).then(...);
Bu yerda biz asl funktsiya ikkita argumentli qayta chaqiruvni kutadi deb oâylaymiz (err, result). Biz tez-tez duch keladigan narsa. Keyin bizning odatiy qaytchaqiruv qilishimiz toâgâri formatga ega va promisify bunday holat uchun juda yaxshi ishlaydi.
Ammo asl f callback(err, res1, res2) ni koâproq argumentlar bilan qayta chaqirishni kutsa nima boâladi?
Koâp sonli qayta chaqiruv natijalarini qaytaradigan promisify modifikatsiyasi:
// promisify(f, true) natijalar massivini olish uchun
function promisify(f, manyArgs = false) {
return function (...args) {
return new Promise((resolve, reject) => {
function callback(err, ...results) { // bizning odatiy callback f uchun
if (err) {
reject(err);
} else {
// manyArgs ko'rsatilgan bo'lsa, barcha callback natijalari bilan hal qiling
resolve(manyArgs ? results : results[0]);
}
}
args.push(callback);
f.call(this, ...args);
});
};
}
// Foydalanish:
f = promisify(f, true);
f(...).then(arrayOfResults => ..., err => ...);
Baâzi hollarda, err umuman yoâq boâlishi mumkin: callback(result), yoki qayta chaqiruv qilish formatida ekzotik narsa boâlsa, biz bunday funktsiyalarni qoâlda vaâda qila olamiz.
Promisifikatsiya funktsiyalaridan biroz moslashuvchan boâlgan modullar ham mavjud, masalan, es6-promisify. Node.js-da buning uchun oârnatilgan util.promisify funktsiyasi mavjud.
Promisifikatsiya â bu ajoyib yondashuv, ayniqsa async/await dan foydalanganda (keyingi bobga qarang), ammo qayta chaqiruvlarni toâliq almashtirish emas.
Yodda tuting, vaâda faqat bitta natijaga ega boâlishi mumkin, ammo texnik qayta chaqiruv koâp marta chaqirilishi mumkin.
Shunday qilib, promisifikatsiya faqat qayta chaqiruvni chaqiradigan funktsiyalar uchun moâljallangan. Boshqa chaqiruvlar eâtiborga olinmaydi.

Izohlar
<code>yorlig'ini ishlating, bir nechta satrlar uchun - ularni<pre>yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepenâ¦)