最近一段時間一直在看Node.js,在開發過程當中常常要調用一些異步接口,一般在接口的最後一個參數會傳入一個回調函數,能夠用來處理異常,非異常狀況。大體模式以下:javascript
1 var fs = require(「fs"); 2 fs.readFile(filename, "binary", function(err, file){ 3 if(err){ 4 //異常狀況 5 }else{ 6 //正常狀況 7 } 8 });
可是,這種寫法趕上比較複雜的邏輯時,就很容易出現 callback hell的問題。html
Node.js須要按順序執行異步邏輯時通常採用後續傳遞風格,也就是將後續邏輯封裝在回調函數中做爲起始函數的參數,逐層嵌套。這種風格雖然能夠提升 CPU利用率,下降等待時間,但當後續邏輯步驟較多時會影響代碼的可讀性,結果代碼的修改維護變得很困難。根據這種代碼的樣子,通常稱其 爲"callback hell"java
對異步接口的處理方式都是依賴於Promise,對於上篇文章講到的Fetch,直接返回Promise.promise
如何將callback接口變成Promise接口?babel
var promisify = function promisify(fn, receiver) { return function() { for(var _len = argument.length, args = Array(_len), _key = 0; _key<_len; _key++) { args[_key] = arguments[_key]; } return new Promise(function (resolve, reject) { fn.apply(receiver, [].concat(args,[function(err, res){ return err ? reject(err) : resolve(res); }])); }); }; };
經過 promisify這個函數,就能夠把接口進行轉換。app
上面的模板就能夠改爲下面的形式:異步
1 var fs = require("fs"); 2 var readFilePromise = promisify(fs.readFile, fs); //包裝爲Promise接口 3 readFilePromise(filename, "binary").then(function(file){ 4 //正常狀況 5 }).catch(function(err){ 6 //異常狀況 7 })
特殊狀況函數
有些設計不合理的接口可能會傳遞多個值給回調函數,如:post
1 var fn = function(foo, callback){ 2 if(success){ 3 callback(null, file1, file2); 4 }else{ 5 callback(err); 6 } 7 }
很明顯 這個接口傳了 file1,file2兩個值,是沒有辦法用上述方法的,用了上述接口轉換沒有辦法獲取到file2的數據。性能
對於這種狀況只能手工包裝。
提升性能
可使用高性能的Promise庫來提升性能。如:bluebird。簡單對比測試發現,blurbird 的性能是 V8 裏內置的 Promise 3 倍左右.
替換內置的Promise:
若是項目裏用了 Babel 編譯 ES6 代碼的話,能夠用下面的方式替換:若是項目裏用了 Babel 編譯 ES6 代碼的話,能夠用下面的方式替換:
Babel 用於轉化你的 JavaScript 代碼
你的 JavaScript 代碼是這樣的:
myJavaScript("foobar");
轉化以後的 JavaScript 是這樣的
myNewTransformedJavaScript("yay!");
原文地址:http://welefen.com/post/how-to-convert-callback-to-promise.html