摘要:今天要介紹的是,就是回調(diào)函數(shù)與間的橋梁。什么樣的叫有兩個(gè)條件回調(diào)函數(shù)在主函數(shù)中的參數(shù)位置必須是最后一個(gè)回調(diào)函數(shù)參數(shù)中的第一個(gè)參數(shù)必須是。
作者:晃晃
本文原創(chuàng),轉(zhuǎn)載請(qǐng)注明作者及出處
Promise 自問(wèn)世以來(lái),得到了大量的應(yīng)用,簡(jiǎn)直是 javascript 中的神器。它很好地解決了異步方法的回調(diào)地獄、提供了我們?cè)诋惒椒椒ㄖ惺褂?return 的能力,并將 callback 的調(diào)用納入了自己的管理,而不是交給異步函數(shù)后我們就無(wú)能為力了(經(jīng)常有 callback 被莫名調(diào)用兩次而導(dǎo)致程序出錯(cuò))。
今天要介紹的是 Promisify,就是回調(diào)函數(shù)與 Promise 間的橋梁。
1. promisify 介紹什么是 promisify 呢?顧名思義,就是“promise 化”,將一個(gè)不是promise的方法變成 promise 。舉個(gè)例子:
// 原有的callback調(diào)用 fs.readFile("test.js", function(err, data) { if (!err) { console.log(data); } else { console.log(err); } }); // promisify后 var readFileAsync = promisify(fs.readFile); readFileAsync("test.js").then(data => { console.log(data); }, err => { console.log(err); });
這兩個(gè)方法效果上是等價(jià)的,但是從掌控性來(lái)說(shuō)的話,我更喜歡后面的寫法。
那么什么樣的方法可以通過(guò) promisify 變成 promise 呢?這里就需要介紹一個(gè)名詞,nodeCallback。什么樣的 callback 叫 nodeCallback ?
nodeCallback 有兩個(gè)條件:1. 回調(diào)函數(shù)在主函數(shù)中的參數(shù)位置必須是最后一個(gè);2. 回調(diào)函數(shù)參數(shù)中的第一個(gè)參數(shù)必須是 error 。舉個(gè)例子:
回調(diào)函數(shù)在主函數(shù)中的參數(shù)位置
// 正確 function main(a, b, c, callback) { } // 錯(cuò)誤 function main(callback, a, b, c) { }
回調(diào)函數(shù)參數(shù)中的第一個(gè)參數(shù)必須是 error
// 正確 function callback(error, result1, result2) { } // 錯(cuò)誤 function callback(result1, result2, error) { }
這樣,通過(guò) nodeCallback ,我們定義了一個(gè)能被 promisify 的函數(shù)的格式,即,滿足 nodeCallback 形式的方法,我們可以通過(guò) promisify 來(lái)讓它變成一個(gè)返回 promise 的方法。
2. promisify 的實(shí)現(xiàn)下面我們來(lái)根據(jù)上述條件來(lái)手動(dòng)實(shí)現(xiàn)一個(gè) promisify 。
首先 promisify 需要返回一個(gè) function ,并且這個(gè) function 要返回一個(gè) promise
var promisify = (func) => { return function() { var ctx = this; return new Promise(resolve => { return func.call(ctx, ...arguments); }) } }
其次,原 func 的最后一個(gè)參數(shù)是 callback
var promisify = (func) => { return function() { var ctx = this; return new Promise(resolve => { return func.call(ctx, ...arguments, function() { resolve(arguments); }); }) } }
然后,回調(diào)函數(shù)中的第一個(gè)參數(shù)是 error 標(biāo)記
var promisify = (func) => { return function() { var ctx = this; return new Promise((resolve, reject) => { return func.call(ctx, ...arguments, function() { var args = Array.prototype.map.call(arguments, item => item); var err = args.shift(); if (err) { reject(err); } else { resolve(args); } }); }) } }
最后,做一些優(yōu)化,比如 this 作用域的自定義、回參只有一個(gè)時(shí)不返回?cái)?shù)組
var promisify = (func, ctx) => { // 返回一個(gè)新的function return function() { // 初始化this作用域 var ctx = ctx || this; // 新方法返回的promise return new Promise((resolve, reject) => { // 調(diào)用原來(lái)的非promise方法func,綁定作用域,傳參,以及callback(callback為func的最后一個(gè)參數(shù)) func.call(ctx, ...arguments, function() { // 將回調(diào)函數(shù)中的的第一個(gè)參數(shù)error多帶帶取出 var args = Array.prototype.map.call(arguments, item => item); var err = args.shift(); // 判斷是否有error if (err) { reject(err) } else { // 沒(méi)有error則將后續(xù)參數(shù)resolve出來(lái) args = args.length > 1 ? args : args[0]; resolve(args); } }); }) }; };
測(cè)試
// nodeCallback方法func1 var func1 = function(a, b, c, callback) { callback(null, a+b+c); } // promise化后的func2 var func2 = promisify(func1); // 調(diào)用后輸出6 func1(1, 2, 3, (err, reuslt) => { if (!err) { console.log(result); //輸出6 } }) func2(1, 2, 3).then(console.log); //輸出6
以上便是 promisify 的介紹和實(shí)現(xiàn),事實(shí)上有很多用 callback 來(lái)實(shí)現(xiàn)異步的第三方庫(kù)提供的方法都是按照 nodeCallback 格式的,所以它們都可以通過(guò) promisify 來(lái)讓它變成 promise ,在遇到這些方法的時(shí)候就可以更靈活地使用啦。
iKcamp官網(wǎng):http://www.ikcamp.com
訪問(wèn)官網(wǎng)更快閱讀全部免費(fèi)分享課程:《iKcamp出品|全網(wǎng)最新|微信小程序|基于最新版1.0開(kāi)發(fā)者工具之初中級(jí)培訓(xùn)教程分享》。
包含:文章、視頻、源代碼
【11月11號(hào)】上海iKcamp最新活動(dòng)iKcamp原創(chuàng)新書《移動(dòng)Web前端高效開(kāi)發(fā)實(shí)戰(zhàn)》已在亞馬遜、京東、當(dāng)當(dāng)開(kāi)售。
報(bào)名地址:http://www.huodongxing.com/ev...
與“天天練口語(yǔ)”小程序總榜排名第四、教育類排名第一的研發(fā)團(tuán)隊(duì),面對(duì)面溝通交流。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/89433.html
摘要:自定義的化有那么一些場(chǎng)景,是不能夠直接使用來(lái)進(jìn)行轉(zhuǎn)換的,有大概這么兩種情況沒(méi)有遵循約定的回調(diào)函數(shù)返回多個(gè)參數(shù)的回調(diào)函數(shù)首先是第一個(gè),如果沒(méi)有遵循我們的約定,很可能導(dǎo)致的誤判,得不到正確的反饋。 util.promisify是在node.js 8.x版本中新增的一個(gè)工具,用于將老式的Error first callback轉(zhuǎn)換為Promise對(duì)象,讓老項(xiàng)目改造變得更為輕松。 在官方推...
摘要:參考文檔升級(jí)后的函數(shù)回調(diào)參數(shù)問(wèn)題中的使用方法和還是不一樣的源碼講解的內(nèi)部機(jī)制優(yōu)化相關(guān)內(nèi)容文章官方文檔簡(jiǎn)述使用過(guò)的都知道這個(gè)方法的作用,通過(guò)該方法會(huì)讓形式的函數(shù)風(fēng)格轉(zhuǎn)換成方法,可以認(rèn)為是一顆語(yǔ)法糖,例如接下來(lái)我們就分析一下這個(gè)的內(nèi)部流程。 參考文檔 升級(jí)bluebird 3后Promise.promisify的函數(shù)回調(diào)參數(shù)問(wèn)題:3中的使用方法和2還是不一樣的 How does Bl...
摘要:初學(xué),用開(kāi)發(fā)項(xiàng)目。而且還是個(gè)不小的項(xiàng)目,說(shuō)起來(lái)挺冒險(xiǎn)的。一開(kāi)始比較簡(jiǎn)單,并沒(méi)有使用也能順利進(jìn)行,隨著開(kāi)發(fā)的深入,到了不用不行的地步了。于是產(chǎn)生了一個(gè)問(wèn)題,一些之前寫的方法并不支持,如果直接改成,那之前調(diào)用過(guò)的地方也都得改,工作量有點(diǎn)大。 初學(xué) Node.js,用 Express 開(kāi)發(fā) Web 項(xiàng)目。而且還是個(gè)不小的項(xiàng)目,說(shuō)起來(lái)挺冒險(xiǎn)的。 一開(kāi)始比較簡(jiǎn)單,并沒(méi)有使用 Promise 也能...
摘要:今天碰到一個(gè)需要用做無(wú)窮循環(huán)的一個(gè)案例,頓時(shí)腦洞大開(kāi)。事情是這樣的,有這樣的一群異步函數(shù),將它們封裝成,依次放入一個(gè)數(shù)組內(nèi)需要讓數(shù)組里的每一個(gè)依次進(jìn)行,最后一個(gè)執(zhí)行完就結(jié)束。 今天碰到一個(gè)需要用Promise做無(wú)窮循環(huán)then的一個(gè)案例,頓時(shí)腦洞大開(kāi)。事情是這樣的,有這樣的一群異步函數(shù), var func1 = function(callback){ setTimeout(fu...
摘要:而適配器其實(shí)在中應(yīng)該是比較常見(jiàn)的一種了。在維基百科中,關(guān)于適配器模式的定義為在軟件工程中,適配器模式是一種軟件設(shè)計(jì)模式,允許從另一個(gè)接口使用現(xiàn)有類的接口。 適配器設(shè)計(jì)模式在JavaScript中非常有用,在處理跨瀏覽器兼容問(wèn)題、整合多個(gè)第三方SDK的調(diào)用,都可以看到它的身影。 其實(shí)在日常開(kāi)發(fā)中,很多時(shí)候會(huì)不經(jīng)意間寫出符合某種設(shè)計(jì)模式的代碼,畢竟設(shè)計(jì)模式就是老前輩們總結(jié)提煉出來(lái)的一些能...
閱讀 3174·2021-09-22 15:54
閱讀 4098·2021-09-09 11:34
閱讀 1834·2019-08-30 12:48
閱讀 1222·2019-08-30 11:18
閱讀 3516·2019-08-26 11:48
閱讀 979·2019-08-23 17:50
閱讀 2182·2019-08-23 17:17
閱讀 1313·2019-08-23 17:12