Hogyan írhatunk saját Promisify funkciót a Scratch-ból

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é?

  1. Visszahívások esetén, ha szekvenciálisan szeretne valamit csinálni, akkor errminden 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 .catchmódszert vagy blokkot, amely elkapja az ígéretláncban előforduló hibákat
  2. 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.
  3. 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:

  1. 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.
  2. Promizálás - Hozzunk létre egy util / helper függvényt, promisifyamely á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 getSumAsyncbí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, getSumPromiseamelynek van .thenés .catchmó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 promisifyfü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. argstö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 getSumAsyncfü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 resultfogjuk, rejectvagy   resolveaz í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 getSumAsyncennek 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/rejectennek 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.