Node.js开发指南 Node.js的Promise库-bluebird详解
沉沙 2018-07-25 来源 : 阅读 769 评论 0

摘要:本篇Node.js教程探讨了Node.js的Promise库-bluebird,希望阅读本篇文章以后大家有所收获,帮助大家对Node.js的理解更加深入。

本篇Node.js教程探讨了Node.js的Promise库-bluebird,希望阅读本篇文章以后大家有所收获,帮助大家对Node.js的理解更加深入。

本文本着实用的目的,主要介绍如何将自定义方法转换为Promise方法,将异步方法转换为同步方法调用。

1. 首先定义一些简单的方法,这是一个很简单例子,模拟读取配置文件、打开数据库、创建数据库结构、创建一个用户、读取这个用户、显示这个用户属性的整个过程。此处就不写node.js的回调嵌套了,以免使用手机打开本文时特别惨不忍睹的。

 1 //数据库对象

 2 var db;

 3

 4 //使用配置文件获取连接字符串

 5 var getConn = function(cfg){

 6 }

 7

  8 //创建或打开sqlite3数据库

 9 var openDb =  function(dbConn){

10 }

11

 12 //创建数据库结构

13 var createSchema = function(){

14 }

15

 16 //创建用户

17 var createUser = function(){

18 }

19

 20 //获取用户

21 var getUser = function(id){

22 }

23

 24 //显示用户属性

25 var showUser = function(user){

26 }

2. 首先来看使用bluebird怎么将异步方法变成同步方法执行

 View Code

 查看执行结果,可以看到完全没有问题,所有方法都按照设想流程在执行。

但是会不会有一种可能,数据太小,电脑执行的很快,所以恰好在下一个方法执行之前上一个方法的异步已经执行完成了(这之前也遇到过这种问题),我们通过 setTimeout 来验证一下:把 createUser 方法延迟1000毫秒再执行,看看 getUser 是否还能获取到数据

var createUser = function(){

    return new Promise(function(resolve, reject){

        setTimeout(function(){

            console.log("delay 1000ms");

            db.run("INSERT INTO users (name, password) VALUES ($name, $password)", {$name: "think8848", $password: "111111"}, function(err){

                if(err){

                    reject(err);

                } else{

                    console.log("createUser");

                    resolve(this.lastID);

                }

            });

        }, 1000);

    });

}

查看执行结果,完全没有问题, getUser 方法并没有偷偷提前执行

3. 在刚开始接触bluebird的时候,我有很多疑问。

其中有一个就是:是否仅需将第一个要执行的异步方法实现为Promise模式,其他的方法只需简单的放到 .then() 方法即可?我们来进行实验一下,这里为了代码结构简单点,我仅演示模拟模拟读取配置文件、打开数据库、创建数据库结构、创建一个用户流程,也很能说明问题了。 

 View Code

查看执行结果,貌似也没有问题,全部都按照想像中的顺序执行了,是真的吗?

还是再通过 setTimeout 方法验证下,如果将创建数据库结构的时间推迟,是否还能正确创建用户呢?

var createSchema = function(){

    setTimeout(function(){

        db.serialize(function () {

            var createExpsTable = "CREATE TABLE IF NOT EXISTS expressions ('name' NVARCHAR(20), 'expression' TEXT, 'index' INT, 'likes' INT)";

            var createUserTable = "CREATE TABLE IF NOT EXISTS users ('name' NVARCHAR(20), 'password' VARCHAR(20))";

            db.exec(createExpsTable, function (err) {

                if (err) {

                    throw err;

                } else {

                    console.log("create table expressions");

                }

            });

            db.exec(createUserTable, function (err) {

                if (err) {

                    throw err;

                } else {

                    console.log("create table users");

                }

            });

        });

    }, 1000);

}

查看执行结果:出错了,提示没有找到users表,这说明创建用户方法的执行时间要早于创建数据库结构的执行时间。这表明如果要确保每个方法都顺序执行,那就必须每个方法都是Promise模式。

为了更好的看清楚Promise的执行顺序,下面再次用一个简单的例子和运行结果来展示这个问题

"use strict";

var Promise = require("bluebird");

var first = function(){

    console.log("first");

};

var second = function(){

    console.log("second");

}

var third = function(){

    console.log("third");

}

Promise.resolve().then(first).then(second).then(third);

查看执行结果

修改 second 方法为异步方法

var second = function(){

    setTimeout(function () {

        console.log("second");

    }, 1000);

}

查看执行结果,发现执行顺序已经错了

修改 second 方法为 Promise 方法

var second = function(){

    return new Promise(function(resolve, reject){

        setTimeout(function(){

            console.log("second");

            resolve();

        },1000);

    });

}

查看执行结果,发现顺序又和预期一样了

4.  每个Promise方法都使用这种写法好像有点麻烦,是否有更好的办法呢?在很多bluebird的例子中都给了答案,使用promisify方法,下面我们来看改造后的例子。这里值的一提是的,经实验发现,如果要 promisify 一个方法(这个方法被bluebird官方称之为 nodeFunction ),那么这个方法就必须满足以下签名: function(any arguments..., function callback) nodeFunction ,即:有两个参数,第一个参数是上一个Promise执行后的返回值,第二个参数是回调方法,及时上一个方法没有返回值,那么第一个参数也是不应该省去的。尽可能不要给这个 nodeFunction 方法提供多个参数,如果上一个方法有多个返回值,那么最好将多个返回值封装为一个对象返回。

 View Code

查看执行结果:完全没有问题,妥妥的按照既定的顺序来了。

为了保险,我们再使用 setTimeout 进行验证

var createUser = function(args, callback){

    setTimeout(function () {

        console.log("delay 1000ms");

        db.run("INSERT INTO users (name, password) VALUES ($name, $password)", { $name: "think8848", $password: "111111" }, function (err) {

            if (!err) {

                console.log("createUser");

            }

            //此处向下一个Promise方法提供参数值

            callback(err, this.lastID);

        });

    } ,1000);

}

验证结果:可以看出依旧是按照顺序执行的

 我们再看一个例子:

"use strict";

var Promise = require("bluebird");

function first(cb){

    var str = "first";

    console.log("begin");

    cb(null, str);

}

function second(data,cb){

    var str = "second";

    console.log(data);

    cb(null, str);

}

var firstAsync = Promise.promisify(first);var secondAsync = Promise.promisify(second);

firstAsync().then(secondAsync).then(console.log);

其执行结果如下:

仔细观察我们会发现这个例子中对两个方法使用了promisify方法,按照上面的说明,这两个方法的签应符合 nodeFunction 约定才是,然而第一个方法仅包含一个回调函数参数,并没有包含值参数,我们尝试着加一个:

function first(args, cb){

    var str = "first";

    console.log("begin");

    cb(null, str);

}


本文由职坐标整理发布,学习更多的Node.js相关知识,请关注职坐标WEB前端Node.js频道!

本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程