最近一段时间一直在看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