промисификациялоо жөнөкөй трансформация үчүн узун сөз. Биз кайра чалууну кабыл алган функцияны алып, анын ордуна убаданы кайтаруу үчүн аны өзгөртөбүз.
Мындай трансформациялар көбүнчө реалдуу жашоодо зарыл, анткени көптөгөн функциялар жана китепканалар кайра чалууларга негизделген жана промисификациялоо колдонуу ыңгайлуураак, ошондуктан аларга "промисификациялоо" акылга сыярлык.
Мисалы, бизде Киришүү loadScript(src, callback)
бөлүмүндө бар : кайра чалуулар .
@A@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) => {...})@A@
Келгиле, убада берели. Жаңы функция да loadScriptPromise(src)
ушундай кылат, бирок убаданы гана кабыл алат src
(жок ) жана кайтарат.callback
@A@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(...)@A@
Эми loadScriptPromise
убадага негизделген код менен жакшы шайкеш келет.
Көрүнүп тургандай, ал бардык ишти баштапкы функцияга өткөрүп берет loadScript
, аны кайра чалуу менен камсыз кылат, анын чакыруусу боюнча resolve/reject
убада аткарылат.
Практикада, балким, биз бир нече функцияны алдын ала белгилешибиз керек болот, андыктан бул үчүн атайын “жардамчы функцияны” жасоонун мааниси бар.
Биз аны чакырабыз promisify(f)
- ал убада кылуу функциясын алат f
жана орогуч функциясын кайтарат.
Бул орогуч функциясы жогорудагы коддогудай эле нерсени аткарат: убаданы кайтарып, чалууну оригиналдууга өткөрүп f
, анын кайра чалуудагы натыйжасын көзөмөлдөйт:
@A@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(...);@A@
Бул жерде биз баштапкы функция эки аргумент менен кайра чалууну күтөт деп ойлойбуз (err, result)
. Бул биз эң көп жолугабыз. Анда биздин кайра чалуу туура форматта жана promisify
бул учурда абдан жакшы иштейт.
Бирок оригинал f
көбүрөөк аргументтер менен кайра чалууну күтсө эмне болот callback(err, res1, res2, ...)
?
Жакшыртылган функция төмөндө сүрөттөлөт promisify
: чакырганда, promisify(f, true)
убаданын натыйжасы натыйжалардын массивинде болот [res1, res2, ...]
:
@A@// 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 {
// делаем resolve для всех results колбэка, если задано manyArgs
resolve(manyArgs ? results : results[0]);
}
}
args.push(callback);
f.call(this, ...args);
});
};
};
// использование:
f = promisify(f, true);
f(...).then(arrayOfResults => ..., err => ...)@A@
Көбүрөөк экзотикалык кайра чалуу форматтары үчүн, мисалы err
, : жок callback(result)
, биз функцияларды жардамчысыз, "кол менен" убада кыла алабыз.
Ошондой эле ийкемдүү убадалары бар модулдар бар, мисалы es6-promisifyutil.promisify
же Node.js ичинде орнотулган функция.
Убада берүү - бул эң сонун ыкма, өзгөчө, эгер сиз колдоно турган болсоңуз async/await
(кийинки бөлүмдү караңыз), бирок бул кандайдыр бир кайра чалууларды толук алмаштыруу эмес.
Эсиңизде болсун, убада бир гана натыйжага ээ болушу мүмкүн, бирок кайра чалууну техникалык жактан каалаган санда чакырса болот.
Ошондуктан, убада кайра чалууну бир гана жолу чакырган функциялар үчүн колдонулат. Кайра чалууга кийинки чалуулар этибарга алынбайт.