âÐÑомÑÑиÑÑкаÑÑÑâ â Ñе довге Ñлово Ð´Ð»Ñ Ð¿ÑоÑÑÐ¾Ñ ÑÑанÑÑоÑмаÑÑÑ. Це пеÑеÑвоÑÐµÐ½Ð½Ñ ÑÑнкÑÑÑ, Ñка пÑÐ¸Ð¹Ð¼Ð°Ñ ÐºÐ¾Ð»Ð±ÐµÐº Ñа повеÑÑÐ°Ñ Ð¿ÑомÑÑ.
Ð¢Ð°ÐºÑ Ð¿ÐµÑеÑвоÑÐµÐ½Ð½Ñ ÑаÑÑо Ð½ÐµÐ¾Ð±Ñ ÑÐ´Ð½Ñ Ð² ÑеалÑÐ½Ð¾Ð¼Ñ Ð¶Ð¸ÑÑÑ, оÑкÑлÑки багаÑо ÑÑнкÑÑй Ñа бÑблÑоÑеки заÑÐ½Ð¾Ð²Ð°Ð½Ñ Ð½Ð° ÐºÐ¾Ð»Ð±ÐµÐºÐ°Ñ , а викоÑиÑÑÐ°Ð½Ð½Ñ Ð¿ÑомÑÑÑв зÑÑÑнÑÑе, ÑÐ¾Ð¼Ñ Ñ ÑÐµÐ½Ñ Â«Ð¿ÑомÑÑиÑÑкÑваÑи» ÑÑ .
ÐÐ»Ñ ÐºÑаÑого ÑозÑмÑÐ½Ð½Ñ ÑозглÑнемо пÑиклад.
Ðи вÑзÑмемо loadScript(src, callback) з ÑоздÑÐ»Ñ ÐведеннÑ: колбеки.
function loadScript(src, callback) {
let script = document.createElement('script');
script.src = src;
script.onload = () => callback(null, script);
script.onerror = () => callback(new Error(`Ðомилка заванÑÐ°Ð¶ÐµÐ½Ð½Ñ ÑкÑипÑа ${src}`));
document.head.append(script);
}
// викоÑиÑÑаннÑ:
// loadScript('path/script.js', (err, script) => {...})
ФÑнкÑÑÑ Ð·Ð°Ð²Ð°Ð½ÑажÑÑ ÑкÑÐ¸Ð¿Ñ Ð²Ð¸ÐºÐ¾ÑиÑÑовÑÑÑи аÑгÑÐ¼ÐµÐ½Ñ src, а поÑÑм Ð²Ð¸ÐºÐ»Ð¸ÐºÐ°Ñ callback(err) Ñ Ð²Ð¸Ð¿Ð°Ð´ÐºÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ¸ Ñи callback(null, script) Ñ Ð²Ð¸Ð¿Ð°Ð´ÐºÑ ÑÑпÑÑного заванÑаженнÑ. Це ÑÑÑм вÑдоме викоÑиÑÑÐ°Ð½Ð½Ñ ÐºÐ¾Ð»Ð±ÐµÐºÑ, Ñке ми вже баÑили.
ÐавайÑе пÑомÑÑиÑÑкÑÑмо ÑÑ ÑÑнкÑÑÑ.
СÑвоÑимо Ð½Ð¾Ð²Ñ ÑÑнкÑÑÑ loadScriptPromise(src), Ñка ÑобиÑÑ Ñе Ñаме (заванÑажÑÑ ÑкÑипÑ), але повеÑÑÐ°Ñ Ð¿ÑомÑÑ Ð·Ð°Ð¼ÑÑÑÑ Ð²Ð¸ÐºÐ¾ÑиÑÑÐ°Ð½Ð½Ñ ÐºÐ¾Ð»Ð±ÐµÐºÑ.
ÐнÑими Ñловами, ми бÑдемо пеÑедаваÑи ÑÑлÑки src (не callback) Ñ Ð¾ÑÑимаÑмо пÑомÑÑ Ñ Ð²ÑдповÑдÑ, Ñкий повеÑне script коли заванÑÐ°Ð¶ÐµÐ½Ð½Ñ ÑÑпÑÑне, Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÑ, ÑкÑо нÑ.
РеалÑзаÑÑÑ ÑÐ°ÐºÐ¾Ñ ÑÑнкÑÑÑ:
let loadScriptPromise = function(src) {
return new Promise((resolve, reject) => {
loadScript(src, (err, script) => {
if (err) reject(err);
else resolve(script);
});
});
};
// викоÑиÑÑаннÑ:
// loadScriptPromise('path/script.js').then(...)
Як ви можеÑе баÑиÑи, нова ÑÑнкÑÑÑ â Ñе обгоÑÑка оÑигÑналÑÐ½Ð¾Ñ loadScript ÑÑнкÑÑÑ. Ðона Ð²Ð¸ÐºÐ»Ð¸ÐºÐ°Ñ Ð²Ð»Ð°Ñний колбек, Ñкий пÑаÑÑÑ Ð· ÑÑнкÑÑÑми пÑомÑÑа resolve/reject.
Як баÑимо, ÑÑнкÑÑÑ loadScriptPromise добÑе впиÑÑÑÑÑÑÑ Ð² аÑинÑ
ÑÐ¾Ð½Ð½Ñ Ð¿Ð¾Ð²ÐµÐ´ÑÐ½ÐºÑ Ð¿ÑомÑÑÑв.
Ðа пÑакÑиÑÑ Ð½Ð°Ð¼, ÑвидÑе за вÑе, знадобиÑÑÑÑ Ð¿ÑомÑÑиÑÑкÑваÑи не Ð¾Ð´Ð½Ñ ÑÑнкÑÑÑ, ÑÐ¾Ð¼Ñ Ñ ÑÐµÐ½Ñ Ð·ÑобиÑи Ð´Ð»Ñ ÑÑого ÑпеÑÑалÑÐ½Ñ Â«ÑÑнкÑÑÑ-помÑÑник».
Ðи назвемо ÑÑ promisify(f) â вона пÑÐ¸Ð¹Ð¼Ð°Ñ ÑÑнкÑÑÑ Ð´Ð»Ñ Ð¿ÑомÑÑиÑÑкаÑÑÑ f Ñа повеÑÑÐ°Ñ ÑÑнкÑÑÑ-обгоÑÑкÑ.
function promisify(f) {
return function (...args) { // повеÑÑÐ°Ñ ÑÑнкÑÑ-обгоÑÑÐºÑ (*)
return new Promise((resolve, reject) => {
function callback(err, result) { // Ð½Ð°Ñ ÑпеÑÑалÑний колбек Ð´Ð»Ñ f (**)
if (err) {
reject(err);
} else {
resolve(result);
}
}
args.push(callback); // додаÑмо колбек Ñ ÐºÑнеÑÑ Ð°ÑгÑменÑÑв f
f.call(this, ...args); // викликаÑмо оÑигÑналÑÐ½Ñ ÑÑнкÑÑÑ
});
};
}
// викоÑиÑÑаннÑ:
let loadScriptPromise = promisify(loadScript);
loadScriptPromise(...).then(...);
Ðод може виглÑдаÑи деÑо Ñкладним, але по ÑÑÑÑ Ð²Ñн Ñакий Ñамий, Ñк ми напиÑали виÑе, пÑомÑÑиÑÑкÑÑÑи ÑÑнкÑÑÑ loadScript.
Ðиклик ÑÑнкÑÑÑ promisify(f) повеÑне ÑÑнкÑÑÑ-обгоÑÑÐºÑ Ð´Ð»Ñ f (*). Ð¦Ñ Ð¾Ð±Ð³Ð¾ÑÑка повеÑÑÐ°Ñ Ð¿ÑомÑÑ Ñ Ð²Ð¸ÐºÐ»Ð¸ÐºÐ°Ñ Ð¾ÑигÑналÑÐ½Ñ ÑÑнкÑÑÑ f, вÑдÑÑежÑÑÑи ÑезÑлÑÑÐ°Ñ Ñ ÑпеÑÑалÑÐ½Ð¾Ð¼Ñ Ð·Ð²Ð¾ÑоÑÐ½Ð¾Ð¼Ñ Ð²Ð¸ÐºÐ»Ð¸ÐºÑ (**).
Ð ÑÑÐ¾Ð¼Ñ Ð²Ð¸Ð¿Ð°Ð´ÐºÑ, promisify пÑипÑÑкаÑ, Ñо оÑигÑналÑна ÑÑнкÑÑÑ Ð¾ÑÑкÑÑ ÐºÐ¾Ð»Ð±ÐµÐº ÑÑлÑки з двома аÑгÑменÑами (err, result). Ð Ñаким ÑезÑлÑÑаÑом ÐºÐ¾Ð»Ð±ÐµÐºÑ Ð²Ð¸ пÑаÑÑваÑимеÑе найÑаÑÑÑÑе. Ð ÑÐ°ÐºÐ¾Ð¼Ñ Ð²Ð¸Ð¿Ð°Ð´ÐºÑ Ð½Ð°Ñ ÐºÐ¾Ð»Ð±ÐµÐº напиÑаний Ñ Ð²ÑдпÑаÑÑовÑваÑиме пÑавилÑно.
Ðле Ñо, ÑкÑо виÑ
Ñдна ÑÑнкÑÑÑ f оÑÑкÑÑ ÐºÐ¾Ð»Ð±ÐµÐº з бÑлÑÑÐ¾Ñ ÐºÑлÑкÑÑÑÑ Ð°ÑгÑменÑÑв callback(err, res1, res2, ...)?
Ðи можемо покÑаÑиÑи наÑÑ ÑÑнкÑÑÑ-помÑÑник. ÐÑобÑмо ÑозÑиÑÐµÐ½Ñ Ð²ÐµÑÑÑÑ promisify.
- ÐиклиÑмо ÑÑнкÑÑÑ
promisify(f)з одним аÑгÑменÑом, Ñо вона повинна пÑаÑÑваÑи Ñк Ñ ÑанÑÑе. - ÐиклиÑмо ÑÑнкÑÑÑ
promisify(f, true)з двома аÑгÑменÑами, Ñка повинна повеÑнÑÑи пÑомÑÑ, Ñкий повеÑне маÑив ÑезÑлÑÑаÑÑв з колбекÑ. Те ж Ñаме повинно вÑдбÑваÑиÑÑ Ð´Ð»Ñ ÐºÐ¾Ð»Ð±ÐµÐºÑ Ð· багаÑÑма аÑгÑменÑами.
// promisify(f, true) повинна повеÑнÑÑи маÑив ÑезÑлÑÑаÑÑв
function promisify(f, manyArgs = false) {
return function (...args) {
return new Promise((resolve, reject) => {
function callback(err, ...results) { // Ð½Ð°Ñ ÑпеÑÑалÑний колбек Ð´Ð»Ñ f
if (err) {
reject(err);
} else {
// повеÑнемо Ð´Ð»Ñ Ð²ÑÑ ÑезÑлÑÑаÑи колбека, ÑкÑо задано знаÑÐµÐ½Ð½Ñ manyArgs === true
resolve(manyArgs ? results : results[0]);
}
}
args.push(callback);
f.call(this, ...args);
});
};
}
// викоÑиÑÑаннÑ:
f = promisify(f, true);
f(...).then(arrayOfResults => ..., err => ...);
Як ви можеÑе баÑиÑи, Ñе по ÑÑÑÑ Ñе Ñаме, Ñо й виÑе, але resolve викликаÑÑÑÑÑ Ð»Ð¸Ñе з одним або з ÑÑÑма аÑгÑменÑами залежно вÑд Ñого, Ñи Ñ manyArgs ÑÑÑинним.
ÐÐ»Ñ Ð±ÑлÑÑ ÐµÐºÐ·Ð¾ÑиÑниÑ
ÑоÑмаÑÑв колбека, напÑиклад, без err: callback(result), ми можемо пÑомÑÑиÑÑкÑваÑи ÑÑнкÑÑÑ Ð±ÐµÐ· помÑÑника, «вÑÑÑнÑ».
ÐÑнÑÑÑÑ Ñакож модÑÐ»Ñ Ð· бÑлÑÑ Ð³Ð½ÑÑÐºÐ¾Ñ Ð¿ÑомÑÑиÑÑкаÑÑÑÑ, напÑиклад, es6-promisify або вбÑдована ÑÑнкÑÑÑ util.promisify в Node.js.
ÐÑомÑÑиÑÑкаÑÑÑ â- Ñе ÑÑдовий пÑдÑ
Ñд, оÑобливо ÑкÑо ви бÑдеÑе викоÑиÑÑовÑваÑи async/await (ÑозглÑнемо пÑзнÑÑе в ÑоздÑÐ»Ñ Async/await), але вона не Ñ Ð¿Ð¾Ð²Ð½Ð¾ÑÑнно замÑÐ½Ð¾Ñ Ð±ÑдÑ-ÑкиÑ
колбекÑв.
ÐамâÑÑайÑе, пÑомÑÑ Ð¼Ð¾Ð¶Ðµ маÑи лиÑе один ÑезÑлÑÑаÑ, але колбек ÑÐµÑ Ð½ÑÑно може викликаÑиÑÑ ÑкÑлÑки завгодно ÑазÑв.
Ð¢Ð¾Ð¼Ñ Ð¿ÑомÑÑиÑÑкаÑÑÑ Ð²Ð¸ÐºÐ¾ÑиÑÑовÑÑÑÑÑÑ Ð´Ð»Ñ ÑÑнкÑÑй, Ñо викликаÑÑÑ ÐºÐ¾Ð»Ð±ÐµÐº лиÑе один Ñаз. ÐаÑÑÑÐ¿Ð½Ñ Ð²Ð¸ÐºÐ»Ð¸ÐºÐ¸ колбека бÑдÑÑÑ Ð¿ÑоÑгноÑованÑ.

ÐоменÑаÑÑ
<code>, Ð´Ð»Ñ ÐºÑлÑÐºÐ¾Ñ ÑÑдкÑв â обгоÑнÑÑÑ ÑÑ Ñегом<pre>, Ð´Ð»Ñ Ð¿Ð¾Ð½Ð°Ð´ 10 ÑÑдкÑв â викоÑиÑÑовÑйÑе пÑÑоÑниÑÑ (plnkr, jsbin, codepenâ¦)