Nodejs Q promise库

前言

Q库为nodejs提供了一个基于promise的编程方式,从此避免了一层又一层的callback调用。不过Q的灵活性也给我造成了很大困扰,我可以用promise去resolve promise么,我在then里return promise可以么?因此我研究了下Q库的源代码,幸运的是,Q库提供了一份详细的设计文档,极大的方便了我们对其设计思路的理解。

正文

跳过一些最原始的版本,我们先看看根据promise的最基本工作方式,能想到的最简单的promise实现。

	var defer = function () {
var pending = [], value;
return {
resolve: function (_value) {
value = _value;
for (var i = 0, ii = pending.length; i < ii; i++) {
var callback = pending[i];
callback(value);
}
pending = undefined;
},
then: function (callback) {
if (pending) {
pending.push(callback);
} else {
callback(value);
}
}
}
};

在defer里存储函数,传递到then里的callback会在原defer被resolve时触发,这是最直观的promise实现方式。

这种实现方式无法实现链接,defer.promise.then.then.then是不能实现的,另外defer.resolve只能用实值而不能用promise。

为了能够将promise链接起来,then函数必须也return一个promise,为了能够用promise去resolve defer。q提供了一个对实值的封装。

	var ref = function (value) {
if (value && typeof value.then === "function")
return value;
return {
then: function (callback) {
callback(value);
}};
};

如果value本身为promise,就返回该promise,如果该value为实值,就返回一个已经被resolve了的promise,resolve value就是这个实值。

	var ref = function (value) {
if (value && typeof value.then === "function")
return value;
return {
then: function (callback) {
return ref(callback(value));
}};
};

这个版本将callback的返回值也封装成promise,因此then函数的返回值可以继续用then继续链接下去。不过我们还没法用promise去resolve defer,因此引出了下面这个版本。

	var defer = function () {
var pending = [], value;
return {
resolve: function (_value) {
if (pending) {
value = ref(_value); // values wrapped in a promise
for (var i = 0, ii = pending.length; i < ii; i++) {
var callback = pending[i];
value.then(callback); // then called instead
}
pending = undefined;
}
},
promise: {
then: function (_callback) {
var result = defer();
// callback is wrapped so that its return
// value is captured and used to resolve the promise
// that "then" returns
var callback = function (value) {
result.resolve(_callback(value));
};
if (pending) {
pending.push(callback);
} else {
value.then(callback);
}
return result.promise;
}
}
};
};

在resolve一个defer时,defer会将该value封装成一个promise。然后会将目前存储的callbacks传递到该promise的then函数中,callback函数的调用时机取决于该promise的resolve时刻了。

注意,这里存储的callback也不是通过then函数传递进来的callback了,为了实现then的链接,存储的callback做的实际事情是调用传递进来的callback,并且用结果去resolve内部新建的一个defer,并且then函数返回该新建defer的promise。

简而言之,then里面传递的callback函数也可以返回一个promise,之后的then链里只有在该promise被resolve时才会被调用。

因此现在我们的q库可以写出如下的调用方式:

	var deferA = q.defer();
deferA.promise //promiseA
.then(function(value){
//func1
return promise2;
})
.then(function(value){
//func2
return promise3;
});
defer.resolve(promise1);

这套函数会构造出一个链条:

 deferA ->promiseA -> hidden_deferA -> call func1 -> promise2 -> hidden_defer2 -> call func2 -> promise3

也就是说,每次对一个promise调用then时,它就会创建一个隐藏的defer,返回这个defer的promise,当原promise被resolve时,该defer也会被传递进去的函数生成的结果resolve。

到这一步为止,就是q的promise的大概实现原理了。然而q为了进一步抽象和提高,做出了一个message机制,以后的文章再仔细研究。

Nodejs Q promise设计思路的更多相关文章

  1. angular $q promise详解

    前言 通过本文,你大概能清楚angular promise是个啥,$q又是个啥,以及怎么用它.这里咱们先灌输下promise的思想. 下面写的全是废话,一些看着高逼格其实没什么大作用的概念,想知道$q ...

  2. IM开发基础知识补课(七):主流移动端账号登录方式的原理及设计思路

    1.引言 在即时通讯网经常能看到各种高大上的高并发.分布式.高性能架构设计方面的文章,平时大家参加的众多开发者大会,主题也都是各种高大上的话题——什么5G啦.AI人工智能啦.什么阿里双11分分钟多少万 ...

  3. TYPESDK手游聚合SDK服务端设计思路与架构之一:应用场景分析

    TYPESDK 服务端设计思路与架构之一:应用场景分析 作为一个渠道SDK统一接入框架,TYPESDK从一开始,所面对的需求场景就是多款游戏,通过一个统一的SDK服务端,能够同时接入几十个甚至几百个各 ...

  4. 分享一个CQRS/ES架构中基于写文件的EventStore的设计思路

    最近打算用C#实现一个基于文件的EventStore. 什么是EventStore 关于什么是EventStore,如果还不清楚的朋友可以去了解下CQRS/Event Sourcing这种架构,我博客 ...

  5. ENode框架单台机器在处理Command时的设计思路

    设计目标 尽量快的处理命令和事件,保证吞吐量: 处理完一个命令后不需要等待命令产生的事件持久化完成就能处理下一个命令,从而保证领域内的业务逻辑处理不依赖于持久化IO,实现真正的in-memory: 保 ...

  6. WebGIS中快速整合管理多源矢量服务以及服务权限控制的一种设计思路

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 在真实项目中,往往GIS服务数据源被其他多个信息中心或者第三方 ...

  7. OpenStack 通用设计思路 - 每天5分钟玩转 OpenStack(25)

    API 前端服务 每个 OpenStack 组件可能包含若干子服务,其中必定有一个 API 服务负责接收客户请求. 以 Nova 为例,nova-api 作为 Nova 组件对外的唯一窗口,向客户暴露 ...

  8. Redis入门指南(第2版) Redis设计思路学习与总结

    https://www.qcloud.com/community/article/222 宋增宽,腾讯工程师,16年毕业加入腾讯,从事海量服务后台设计与研发工作,现在负责QQ群后台等项目,喜欢研究技术 ...

  9. MVC3 数据验证用法之密码验证设计思路

    描述:MVC数据验证使用小结 内容:display,Required,stringLength,Remote,compare,RegularExpression 本人最近在公司用mvc做了一个修改密码 ...

随机推荐

  1. Echarts树图定制详解

    本文讲的是如何定制Echarts的tree图.主要包括下载.全局变量名修改.左键菜单添加.右键菜单添加.内容缩放.文本过滤高亮等. 一 说明 Echarts中提供了tree图,但实际项目中,该tree ...

  2. SqlServer SqlBulkCopy批量插入 -- 多张表同时插入(事务)

    这段时间在解决一个多个表需要同时插入大量数据的问题,于是在网上找了下,查到说用SqlBulkCopy效率很高,实验后确实很快,10万条数据只要4秒钟,用ef要用40秒.但是我的还需两张表同时插入,且需 ...

  3. pycharm修改选中字体颜色

    File->Setting->Editor->Color Scheme->General Scheme:Monokai 在方框内: Editor->Section Bac ...

  4. SSH三大框架的搭建整合(struts2+spring+hibernate)

    本文转载自:https://blog.csdn.net/kyle0349/article/details/51751913

  5. 宏表达式与函数、#undef、条件编译、

    宏表达式在预编译期被处理,编译器不知道宏表达式的存在. 宏表达式没有任何的调用开销 宏表达式中不能出现递归定义. C语言中强大的内置宏 __FILE__:被编译的文件名 //双底线 __LINE__: ...

  6. 理解java动态代理

    java动态代理是java语言的一项高级特性.在平时的项目开发中,可能很难遇到动态代理的案例.但是动态代理在很多框架中起着不可替代的作用,例如Spring的AOP.今天我们就聊一聊java动态代理的实 ...

  7. Java泛型三:Java泛型详解

    原文地址https://www.cnblogs.com/lzq198754/p/5780426.html 1.为什么需要泛型 泛型在Java中有很重要的地位,网上很多文章罗列各种理论,不便于理解,本篇 ...

  8. javascript面向对象笔记(一)

    ECMAscript对象(以下简称对象): ECMA-262把对象定义为:无序属性的集合,其属性可以包含基本值.对象或者函数. 对象的每个属性或方法都有一个名字,而每个名字都映射到一个值.值可以是数据 ...

  9. XDU 1003 B进制加法(高精度)

    #include<bits/stdc++.h> using namespace std; long long mpow(long long a,long long b) { ; ) ; w ...

  10. JVM类加载机制(转)

    原文出自:http://www.cnblogs.com/ityouknow/p/5603287.html 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运 ...