最近一段时间一直在看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. Ajax跨域的几种方法以及每种方法的原理

    js中几种实用的跨域方法原理详解 这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协 ...

  2. c#中事物使用

    数据库事务(简称: 事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成.当事务被提交给了DBMS(数据库管理系统),则DBMS(数据库管理系统)需要确保该事务中的所有操作都 ...

  3. final review 报告

    项目名:约跑 组名:nice! 组长:李权 组员:刘芳芳于淼韩媛媛 宫丽君 final Review会议 时间:2016.12.2  代码git的地址:https://git.coding.net/m ...

  4. CentOS手动编译安装gcc

    最近尝试了fedora.ubuntu.mint.debian.opensuse等多种linux发行版,与CentOS比较之后还是感觉之前用的CentOS比较熟悉,比较习惯.现在CentOS的最新版本为 ...

  5. asp.net mvc4 MvcMusicStore

    最近危机感紧迫,总想学些东西.又因为之前mvc的知识不够系统和牢固,所以最近想系统的过一遍.自然买了两本书来看,一边看一边对比.尽量做到每个地方都过一下.今天遇到一个问题所以记一下博客. 环境:win ...

  6. java context 讲解

    在 java 中, 常见的 Context 有很多, 像: ServletContext, ActionContext, ServletActionContext, ApplicationContex ...

  7. 【转】PowerShell入门(十一):编写脚本模块

    转至:http://www.cnblogs.com/ceachy/archive/2013/03/08/PowerShell_Script_Module.html 现在通过编写模块就可以在PowerS ...

  8. Azure Web Site 之 利用Azure Web site 发布网站

    由于经常混迹于MSDN Azure论坛,少不了和一些外国朋友打交道.有的时候觉得还是有一些东西可以写出来与外国友人们分享下的, 所以就用一个开源项目建了一个英文blog项目. 在发布的时候,首选的就是 ...

  9. php常用string函数

    http://www.w3school.com.cn/php/php_ref_string.asp1.addcslashes() 返回在指定的字符前添加反斜杠的字符串2.addslashes() 返回 ...

  10. CountDownLatch和CyclicBarrier 举例详解

    有时候会有这样的需求,多个线程同时工作,然后其中几个可以随意并发执行,但有一个线程需要等其他线程工作结束后,才能开始.举个例子,开启多个线程分块下载一个大文件,每个线程只下载固定的一截,最后由另外一个 ...