Bevezetés
Ebben a cikkben megtudhatja, hogyan írhatja le saját ígérete funkcióját a semmiből.
Az ígéretek segítenek a visszahívás-alapú API-k kezelésében, miközben a kód megfelel az ígéreteknek.
Bármelyik funkciót be tudnánk tekerni, new Promise()
és egyáltalán nem aggódhatunk emiatt. De ha ezt sok funkcióval látnánk el, akkor felesleges lenne.
Ha megértette az ígéreteket és a visszahívásokat, akkor az ígéretes függvények megírásának megtanulása egyszerű lehet. Tehát kezdjük.
De elgondolkodott már azon, hogy az ígéretes hogyan működik?
Az a fontos, hogy ne hagyjuk abba a kérdezősködést. A kíváncsiságnak megvan a maga oka a létezésre.- Albert Einstein
Az ígéreteket az ECMA-262 szabvány 6. kiadása (ES6) vezette be, amelyet 2015 júniusában tettek közzé.
Ez elég nagy előrelépés volt a visszahívásokkal szemben, mivel mindannyian tudjuk, mennyire olvashatatlan lehet a "visszahívási pokol" :)

Node.js fejlesztőként tudnia kell, hogy mi az ígéret és hogyan működik belsőleg, ami a JS-interjúkban is segítséget nyújt. Mielőtt továbbolvasna, nyugodtan nézze át őket.
Miért kell átalakítanunk a visszahívásokat ígéretekké?
- Visszahívások esetén, ha szekvenciálisan szeretne valamit csinálni, akkor
err
minden visszahívásnál meg kell adnia egy argumentumot, amely felesleges. Az ígéretekben vagy az aszinkron-várakozásban egyszerűen hozzáadhat egy.catch
módszert vagy blokkot, amely elkapja az ígéretláncban előforduló hibákat - Visszahívások esetén nem tudja ellenőrizni, hogy mikor hívják, milyen kontextusban vagy hányszor hívják, ami memóriaszivárgásokhoz vezethet.
- Az ígéretek felhasználásával kontrolláljuk ezeket a tényezőket (különösen a hibakezelést), így a kód olvashatóbb és karbantarthatóbb.
A visszahívás-alapú függvények megígérése
Kétféle módon lehet megtenni:
- Csomagolja be a függvényt egy másik függvénybe, amely ígéretet ad vissza. Ezután visszahívási argumentumok alapján megoldja vagy elutasítja.
- Promizálás - Hozzunk létre egy util / helper függvényt,
promisify
amely átalakítja az összes hiba első visszahívás alapú API-t.
Példa: van egy visszahívás-alapú API, amely két szám összegét adja meg. Meg akarjuk ígérni, így thenable
ígéretet ad vissza .
const getSumAsync = (num1, num2, callback) => { if (!num1 || !num2) { return callback(new Error("Missing arguments"), null); } return callback(null, num1 + num2); } getSumAsync(1, 1, (err, result) => { if (err){ doSomethingWithError(err) }else { console.log(result) // 2 } })
Ígéretbe burkolni
Amint láthatja, az getSumPromise
összes munkát az eredeti funkcióra getSumAsync
bízza, megadva a saját visszahívását, amely ígéretnek felel meg resolve/reject
.
Ígérje meg
Amikor sok funkciót kell ígérnünk, létrehozhatunk egy segítő funkciót promisify
.
Mi az ígéret?
Az ígéretek átalakulást jelentenek. Ez egy olyan függvény átalakítása, amely visszahívást fogad el ígéretet adó funkcióvá.
A Node.js használatával util.promisify()
:
const { promisify } = require('util') const getSumPromise = promisify(getSumAsync) // step 1 getSumPromise(1, 1) // step 2 .then(result => { console.log(result) }) .catch(err =>{ doSomethingWithError(err); })
Tehát úgy néz ki, mint egy mágikus funkció, amely átalakul getSumAsync
, getSumPromise
amelynek van .then
és .catch
módszere
Írjuk meg a saját ígéretes függvényünket:
Ha megnézzük a fenti kód 1. lépését , akkor a promisify
függvény elfogadja a függvényt argumentumként, így először meg kell írnunk egy függvényt, amely ugyanezt megteheti:
const getSumPromise = myPromisify(getSumAsync) const myPromisify = (fn) => {}
Ezután getSumPromise(1, 1)
egy függvényhívás. Ez azt jelenti, hogy az ígéretünknek vissza kell adnia egy másik függvényt, amelyet az eredeti függvény ugyanazon argumentumaival lehet meghívni:
const myPromisify = (fn) => { return (...args) => { } }
A fenti kódban láthatja, hogy argumentumokat terjesztünk, mert nem tudjuk, hány argumentuma van az eredeti függvénynek. args
tömb lesz, amely tartalmazza az összes argumentumot.
Amikor hív, getSumPromise(1, 1)
akkor valóban hív (...args)=> {}
. A fenti megvalósításban ígéretet ad. Ezért tudod használni getSumPromise(1, 1).then(..).catch(..)
.
Remélem kapta azt a tippet, hogy a burkoló funkciónak (...args) => {}
ígéretet kell hoznia.
Adjon vissza ígéretet
const myPromisify = (fn) => { return (...args) => { return new Promise((resolve, reject) => { }) } }
Most az a bonyolult rész, hogy miként lehet eldönteni, mikor kell resolve or reject
ígéretet tenni.
Valójában ezt az eredeti getSumAsync
függvény megvalósítása fogja eldönteni - meghívja az eredeti visszahívási függvényt, és csak meg kell határoznunk. Majd alapján err
és result
fogjuk, reject
vagy resolve
az ígéretet.
const myPromisify = (fn) => { return (...args) => { return new Promise((resolve, reject) => { function customCallback(err, result) { if (err) { reject(err) }else { resolve(result); } } }) } }
A args[]
csak áll érvek telt el getSumPromise(1, 1)
, kivéve, hogy a visszahívási funkció. Tehát hozzá kell adnia azt customCallback(err, result)
, args[]
amelyet az eredeti függvény getSumAsync
ennek megfelelően fog meghívni, miközben nyomon követjük az eredményt customCallback
.
Nyomja meg a customCallback-t argumentumokhoz []
const myPromisify = (fn) => { return (...args) => { return new Promise((resolve, reject) => { function customCallback(err, result) { if (err) { reject(err) }else { resolve(result); } } args.push(customCallback) fn.call(this, ...args) }) } }
Amint láthatja, hozzáadtuk fn.call(this, args)
, amely az eredeti függvényt ugyanabban a kontextusban fogja meghívni az argumentumokkal getSumAsync(1, 1, customCallback)
. Ekkor az ígéretes funkciónknak képesnek kell lennie resolve/reject
ennek megfelelő működésre .
The above implementation will work when the original function expects a callback with two arguments, (err, result)
. That’s what we encounter most often. Then our custom callback is in exactly the right format and promisify
works great for such a case.
But what if the original fn
expects a callback with more arguments likecallback(err, result1, result2, ...)
?
In order to make it compatible with that, we need to modify our myPromisify
function which will be an advanced version.
const myPromisify = (fn) => { return (...args) => { return new Promise((resolve, reject) => { function customCallback(err, ...results) { if (err) { return reject(err) } return resolve(results.length === 1 ? results[0] : results) } args.push(customCallback) fn.call(this, ...args) }) } }
Example:
const getSumAsync = (num1, num2, callback) => { if (!num1 || !num2) { return callback(new Error("Missing dependencies"), null); } const sum = num1 + num2; const message = `Sum is ${sum}` return callback(null, sum, message); } const getSumPromise = myPromisify(getSumAsync) getSumPromise(2, 3).then(arrayOfResults) // [6, 'Sum is 6']
That’s all! Thank you for making it this far!
I hope you’re able to grasp the concept. Try to re-read it again. It’s a bit of code to wrap your head around, but not too complex. Let me know if it was helpful ?
Don’t forget to share it with your friends who are starting with Node.js or need to level up their Node.js skills.
References:
//nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original
//github.com/digitaldesignlabs/es6-promisify
You can read other articles like this at 101node.io.