Bluebird中promisify的用法

来源:互联网 发布:k均值聚类算法matlab 编辑:程序博客网 时间:2024/05/16 18:16

Bluebird中promisify的用法

之前应项目需要,在node.js中引入bluebird包学习使用Promise。其链式结构的异步操作容易理解,也减少了回调函数的多层嵌套。网络上对Promise的介绍已经比较全面,这里不再赘述。本文主要从实际工作遇到的问题出发,介绍其promisify方法的使用。

New一个Promise对象的缺点

创建一个新的Promise对象代码如下:

var Promise = require('bluebird');var promiseObj = new Promise(function(resolve, reject) {    var isJudged = false,        result = '';    // some logic deal code    // ...    // get judgement     if (isJudged) {        resolve(result);    }    else if (!isJudged) {        reject('Something wrong');    }});

我们知道Promise对象存在三种状态:Pending,Resolved和Rejected。当我们的代码执行完一系列的操作,最后进行判断需不需要将运算出的结果返还回去,如果需要,那么我们使用resolve(result);这句代码返回结果,如果不需要,那么我们使用reject(‘Something wrong’);这句代码返回错误信息。二者决定我们在使用此Promise对象时的.then方法是进入Resolved状态的Function还是Rejected状态的Function。

var z = promiseObj.then(function(result){    // Resolved }, function(error) {    // Rejected});

从上面代码可以读出,PromiseObj包含一个then方法,then方法中通过自身状态决定使用哪一个回调函数,那么PromiseObj中存在一个属性保存自身的状态,这条状态的值依赖于我们在new Promise对象时所传入的function中的代码。

实际上,我们在new Promise对象时,传入的function中的代码就立即执行了,Promise对象迫不及待地想得到一个状态值(Resolved也好Rejected也好)。在某些场景应用中,这并非我们所想要的。比如在不同流程中都包含同样一个步骤的Promise,在每个流程中我们都需要重新new一个相同的Promise对象来保证每个流程的运转正常。假如我们只使用一个Promise,那么这个Promise在new出来的那一刻起,就获取当前的context变量开始运行,期望得到一种结果状态。而对于不同流程,它们各自的context变量是存在差异的,因而使用同一个Promise对象会产生预估之外的问题,而对不同流程使用不同Promise的做法看上去又相当麻烦且代码冗长。

我们需要一种Promise型的对象(异步且可用.then的形式执行回调函数),这时候我们可以使用promisify方法。

Promisify

promisify旨在解决使用Promise的方式调用那些没有使用Promise的模块中的方法。这么说可能比较绕。请看官网上解释promisify使用方法的一段代码:

var readFile = Promise.promisify(require("fs").readFile);readFile("myfile.js", "utf8").then(function(contents) {    return eval(contents);}).then(function(result) {    console.log("The result of evaluating myfile.js", result);}).catch(SyntaxError, function(e) {    console.log("File had syntax error", e);//Catch any other error}).catch(function(e) {    console.log("Error reading file", e);});

这里将fs模块中读取文件的readFile转化为了Promise形式的异步方法。现实应用这样的场景也不少,我们需要将一个之前定义好的方法转化为异步的形式。下面将详细介绍如何使用promisify。

var Promise = require('bluebird');var normalFn = function(a, b, c, cb) {    /**     *  your own logic code     */    var t = a + b + c;    if (typeof cb == 'function') {        cb('', t);    }};var promisifyFn = Promise.promisify(normalFn);promisifyFn('hello, ', 'world', '!').then(function(result){    console.log(result);}, function(error) {    console.log(error);});

根据上例,我们必须满足以下条件方可使用promisify进行转换。

  • 原方法必须包含回调函数(cb(”, t);
  • 必须执行回调函数,目的是决定在完成中间整块逻辑代码后,获取最终方法的的状态(Resolved或Rejected)以便选择进入哪个真实的.then之后的回调函数。
  • 回调函数第一个参数代表error的信息,第二个参数代表成功时返回的结果。error为空值,则后续可进入Resoleved的方法,若不为空值,则后续进入Rejected方法

不同于声明一个Promise对象,我们在声明一个promisifyFn时并不会立即去执行其间的逻辑代码,而是将一个普通的函数转化为了一个返回Promise对象的函数,当我们真正调用这个函数的时候,其间的代码才真正的运行。

官网对其定义如下:

Promise.promisify(    function(any arguments..., function callback) nodeFunction,    [Object {        multiArgs: boolean=false,        context: any=this    } options]) -> function

我们在使用promisify时可以设定一些参数,比如context执行上下文,和multiArgs。如果multiArgs设定为true,那么我们在执行cb(”, t);时可以传入多个成功的值,即除了第一个参数绑定为error以外,我们可以在后续的参数中加入我们想添加的任何对象。最终这些传入的参数反应为执行Resolved函数的参数,即.then(function(result) { console.log(result); },。multiArgs为true,那么result是cb传入参数的一个数组对象;multiArgs为false,那么result是cb传入参数的第二个,尽管cb会传入大于两个的参数。

0 0
原创粉丝点击