最近一段时间一直在看Node.js,在开发过程中经常要调用一些异步接口,通常在接口的最后一个参数会传入一个回调函数,可以用来处理异常,非异常情况。大致模式如下:

 var fs = require(“fs");
fs.readFile(filename, "binary", function(err, file){
if(err){
//异常情况
}else{
//正常情况
}
});

但是,这种写法遇上比较复杂的逻辑时,就很容易出现 callback hell的问题。

Node.js需要按顺序执行异步逻辑时一般采用后续传递风格,也就是将后续逻辑封装在回调函数中作为起始函数的参数,逐层嵌套。这种风格虽然可以提高 CPU利用率,降低等待时间,但当后续逻辑步骤较多时会影响代码的可读性,结果代码的修改维护变得很困难。根据这种代码的样子,一般称其 为"callback hell"

对异步接口的处理方式都是依赖于Promise,对于上篇文章讲到的Fetch,直接返回Promise.

如何将callback接口变成Promise接口?

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这个函数,就可以把接口进行转换。

上面的模板就可以改成下面的形式:

 var fs = require("fs");
var readFilePromise = promisify(fs.readFile, fs); //包装为Promise接口
readFilePromise(filename, "binary").then(function(file){
//正常情况
}).catch(function(err){
//异常情况
})

特殊情况

有些设计不合理的接口可能会传递多个值给回调函数,如:

 var fn = function(foo, callback){
if(success){
callback(null, file1, file2);
}else{
callback(err);
}
}

很明显 这个接口传了 file1,file2两个值,是没有办法用上述方法的,用了上述接口转换没有办法获取到file2的数据。

对于这种情况只能手工包装。

提高性能

可以使用高性能的Promise库来提高性能。如:bluebird。简单对比测试发现,blurbird 的性能是 V8 里内置的 Promise 3 倍左右.

替换内置的Promise:

  • global.Promise = require("bluebird");

如果项目里用了 Babel 编译 ES6 代码的话,可以用下面的方式替换:如果项目里用了 Babel 编译 ES6 代码的话,可以用下面的方式替换:

  • require("babel-runtime/core-js/promise").default = require("bluebird");
  • global.Promise = require("bluebird");

Babel 用于转化你的 JavaScript 代码

你的 JavaScript 代码是这样的:

myJavaScript("foobar");

转化之后的 JavaScript 是这样的

myNewTransformedJavaScript("yay!");

原文地址:http://welefen.com/post/how-to-convert-callback-to-promise.html

如何把 Callback 接口包装成 Promise 接口的更多相关文章

  1. 把ajax包装成promise的形式(2)

    概述 为了体验promise的原理,我打算自己把ajax包装成promise的形式.主要希望实现下列功能: // 1.使用success和error进行链式调用,并且可以在后面加上无限个 promis ...

  2. 把ajax包装成promise的形式(3)

    概述 为了体验promise的原理,我打算自己把ajax包装成promise的形式.主要希望实现下列功能: // 1.使用success和error进行链式调用,并且可以在后面加上无限个 promis ...

  3. 把ajax包装成promise的形式(1)

    概述 为了体验promise的原理,我打算自己把ajax包装成promise的形式.主要希望实现下列功能: // 1.使用success和error进行链式调用,并且可以在后面加上无限个 promis ...

  4. 使用SWIG将C++接口转换成Java接口

    PS:此文章仅作为个人记录使用,代码属于私密,故无法公开: 以C++类classifier为例,文件保存于百度网盘 https://pan.baidu.com/s/1c2AwhaS(需密码) 系统:U ...

  5. SIP:用Riverbank的SIP创建C++库的Python模块(把自己的C++库包装成Python模块)

    我们发现PyQt做的Python版的PyQt是如此好用,如果想把自己的C++库包装成Python模块该如何实现呢? 这里介绍下用SIP包装C++库时值得参考的功能实现: 需要Python模块中实现C+ ...

  6. Go part 6 接口,接口排序,接口嵌套组合,接口与类型转换,接口断言

    接口 接口是一种协议,比如一个汽车的协议,就应该有 “行驶”,“按喇叭”,“开远光” 等功能(方法),这就是实现汽车的协议规范,完成了汽车的协议规范,就实现了汽车的接口,然后使用接口 接口的定义:本身 ...

  7. 将JAVA API接口 改写成 Python

    AsinSeedApi 不写注释的程序员-加密 将JAVA API接口 改写成 Python JAVA import com.alibaba.fastjson.JSON; import com.ali ...

  8. QQ登录接口(第三方登录接口)

    CI框架 QQ接口(第三方登录接口PHP版) 本帖内容较多,大部分都是源码,要修改的地方只有一个,其他只要复制过去,就可以完美运行.本帖主要针对CI框架,不用下载SDK,按我下面的步骤,建文件,复制代 ...

  9. hibernate核心接口,和扩展接口。回顾笔记,以前没记,现在补上,纯手工敲的。

    hibernate核心接口: 所有的hibernate应用都会访问hibernate的5个核心接口 1,Configuration接口 Configuration用于配置并且根启动Hibernate. ...

随机推荐

  1. 总结运行SSIS包的几种方式

    方式一: 在BIDS里直接跑. 这个BIDS指的就是SQL Server Business Intelligence Development Studio,对于.net开发者来说它就是Visual S ...

  2. MVC之权限管理-网站开发之路

    一.前言 刚到公司没多长时间就开始接触MVC到现在不能说懂了,只能说到达会用这个层次吧,感觉MVC用来写Web还是很强大的,层次清晰. 今天我来写写关于权限管理这一块,自我感觉网站的权限主要分为菜单权 ...

  3. svg gradient

    SVG和canvas中是一样的,都是使用标准的HTML/CSS中的颜色表示方法,这些颜色都可以用于fill和stroke属性. 基本有下面这些定义颜色的方式: 1. 颜色名字: 直接使用颜色名字red ...

  4. Android隐藏状态栏、导航栏

    Android隐藏状态栏.导航栏 private void hideStatusNavigationBar(){ if(Build.VERSION.SDK_INT<16){ this.getWi ...

  5. Win8+VMware12+CentOS7网络设置

    VMware提供了三种将虚拟网卡和物理网卡捆绑起来的方式,即桥接(Bridge)模式,网络地址转换(Network Address Transformation, NAT)模式和主机(Host Onl ...

  6. 【转】移动前端不得不了解的html5 head 头标签

    来源:http://blog.csdn.net/huang100qi/article/details/42596799 本文主要内容来自一丝的常用的 HTML 头部标签和百度FEX的HTML head ...

  7. Global.asax文件说明

    Global.asax是我们的底层文件,第一次的IIS请求都会先去执行它里面的文件,所以学会它里面的函数是非常有必要的.而且我们总是忽略这里的知识点,总觉得这是不必须的,其实我们错了,这里才是程序的根 ...

  8. Masonry 创建Button的简单使用

    代码创建控制器,控件在实际开发中很实用,方便快捷,而Masonry第三方框架更是将代码创建效率提高了很多! 如何代码创建?如何使用第三方框架? 1.首先删除系统自带的SB,详见下图 2.在AppDel ...

  9. SOSO街景地图 API (Javascript)开发教程(1)- 街景

    SOSO街景地图 Javascript API 干什么用的? 你想在网页里嵌入个地图,就需要它了! 另外,它还支持:地点搜索.周边/附近查询.地图标注.公交/驾车路线规划.地理坐标与地址相互转换.地理 ...

  10. Tomcat重启脚本restart.sh停止脚本stop.sh

    Tomcat重启脚本restart.sh停止脚本stop.sh Tomcat本身提供了 startup.sh(启动)shutdown.sh(关闭)脚本,我们在部署中经常会出现死进程形象,无法杀掉进程需 ...