如何把 Callback 接口包装成 Promise 接口

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

1 var fs = require(“fs");
2 fs.readFile(filename, "binary", function(err, file){
3     if(err){
4         //异常情况
5    }else{
6        //正常情况
7     }
8 });            

但是,这种写法遇上比较复杂的逻辑时,就很容易出现 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这个函数,就可以把接口进行转换。

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

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 })

特殊情况

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

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:

  • 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

时间: 2024-08-07 01:22:55

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

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

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

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

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

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

以C++类classifier为例,文件保存于百度网盘 https://pan.baidu.com/s/1c2AwhaS(需密码) 系统:Ubuntu 15.04 参考资料: ubuntu源码安装swig 利用swig转换C++接口到Java接口 SWIG3.0说明文档 编程中出现的错误: java编译时出现undefined symbol:... 此种情况大部分原因是需要在原来的C++库中添加链接某lib....so文件(undefined symbol: _ZN5boost6system15

2.35 Java基础总结①抽象②接口③设计抽象类和接口的原则④接口和抽象类的区别

java基础总结①抽象②接口③设计抽象类和接口的原则④接口和抽象类的区别 一.抽象 abstract作用:不能产生对象,充当父类,强制子类正确实现重写方法和类相比仅有的改变是不能产生对象,其他的都有,包括构造.属性等等任何一个类只要有一个抽象的方法就成了抽象类 抽象方法 public abstract A();①方法是抽象的,这个类也是抽象的:②子类必须重写抽象方法,除非子类也是抽象类 抽象类可以没有抽象方法,但一般不这么设计 二.接口 interface 接口也是Java的一种引用数据类型(J

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

hibernate核心接口: 所有的hibernate应用都会访问hibernate的5个核心接口 1,Configuration接口 Configuration用于配置并且根启动Hibernate.Hibernate应用通过Configuration实例来获取对象-关系映射文件中的元数据,以及动态配置Hibernate的属性,然后创建SessionFactory实例. 2,SessionFactory接口 一个SessionFactory实例对应一个数据存储源,应用从SessionFactor

008.在C#中,显式接口VS隐式接口

原文http://www.codeproject.com/Articles/1000374/Explicit-Interface-VS-Implicit-Interface-in-Csharp (Aty表示本人) 介绍 什么是显式和隐式接口 什么时候需要显式接口 更简洁的方法(ISP:接口隔离原则) 显式接口更多 结论 介绍 文章将讨论下显式接口,讨论它们与隐式接口的区别,以及为什么应该避免使用. 什么是显式和隐式接口 C#中有两种方式来实现接口:显式和隐式 定义如下接口: 当我们隐式的实现该接

液晶电视插有线电视信号线的是哪个接口 HDMI是什么接口

1.液晶电视插有线电视信号线的接口(模拟信号)是射频接口(也叫RF接口,同轴电缆接口,闭路线接口),数字信号就得通过机顶盒转换成模拟信号视频输出至电视,才能正常收看电视节目. 2.电视机或高清机顶盒上的HDMI接口是高清晰度多媒体接口,是一种数字化视频/音频接口技术,是适合影像传输的专用型数字化接口,其可同时传送音频和影像信号,最高数据传输速度为2.25GB/s. 参考资料:http://baike.baidu.com/link?url=fgrrLNitvtnl5L6lqQ4ex5jZ3cv7a

C#的接口基础教程之六 接口转换

C#中不仅支持.Net 平台,而且支持COM平台.为了支持 COM和.Net,C# 包含一种称为属性的独特语言特性.一个属性实际上就是一个 C# 类,它通过修饰源代码来提供元信息.属性使 C# 能够支持特定的技术,如 COM 和 .Net,而不会干扰语言规范本身.C# 提供将COM接口转换为 C#接口的属性类.另一些属性类将 COM类转换为C# 类.执行这些转换不需要任何 IDL 或类工厂. 现在部署的任何COM 组件都可以在接口转换中使用.通常情况下,所需的调整是完全自动进行的. 特别是,可以

阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第1节 常用函数接口_1_函数式接口的概念&amp;函数式接口的定义

没有参数,没有返回值的抽象方法 一个接口中是可以有多个抽象方法的,如果在这里在定义一个method2.这样里面有两个抽象方法就不是函数式接口了. 确保接口中就一个抽象方法的方式 定义接口的实现类,重写里面的抽象方法 重写了以后,方法上加了注解叫做@Override 复制上面的method2到下面改成叫做method3就报错了.错误提示.method3不是一个可重写的方法.这就是注解的作用. 这个时候就 编译失败了,因为里面有两个抽象方法 只保留一个抽象方法,就不会报错了. 一个抽象方法都没有也会