假设一个业务场景:

通过rss地址,获取rss并保存于文件,rss地址保存于文件中。

完成该场景的业务需要完成3个任务:

1.从文件中读取rss地址。

2.获取rss。

3.保存于文件。

最后将这三个任务进行整合。

准备:

存放rss地址的文件,address.txt。

http://programmer.csdn.net/rss_programmer.html

任务1:

读取rss地址文件的内容并通过callback返回。

var getRssAddress = function(path, callback) {
fs.readFile(path, {encoding: 'utf8'}, function (err, data) {
callback(err, data);
});
}

任务2:

通过rss地址get到rss,并通过callback返回错误或数据。

var getRss = function(url, callback) {
var data = '';
http.get(url, function(res) {
res.on('data', function(chrunk) {
data += chrunk;
}); res.on('end', function() {
callback(null, data);
});
}).on('error', function(err) {
callback(err, null);
});
}

任务3:

将rss保存于文件并通过callback返回错误。

var saveRss = function(data, callback) {
fs.writeFile('rss.txt', data, 'utf8', function(err) {
callback(err);
});
}

整合:

getRssAddress('address.txt', function(err, data) {
if(err) {
console.log(err);
return;
} getRss(data, function(err, data) {
if(err) {
console.log(err);
return;
} saveRss(data, function(err) {
if(err) console.log(err);
});
});
});

上面的代码是全异步处理,使用最常见的callback处理异步逻辑的返回,好处是标准写法,大家都能容易接受;坏处是耦合性太强,处理异常麻烦,代码不直观,特别是处理业务逻辑复杂和处理任务多的场景,层层的callback会让人眼冒金星,代码难以维护。

Promise/A规范的实现之一when.js正是针对这样的问题域。

让我们来看一下改造后的代码。

任务1:

var getRssAddress = function(path) {
var deferred = when.defer();
fs.readFile(path, {encoding: 'utf8'}, function (err, data) {
if (err) deferred.reject(err);
deferred.resolve(data);
}); return deferred.promise;
}

任务2:

var getRss = function(url) {
var deferred = when.defer();
var data = '';
http.get(url, function(res) {
res.on('data', function(chrunk) {
data += chrunk;
});
res.on('end', function() {
deferred.resolve(data);
});
}).on('error', function(err) {
deferred.reject(err);
}); return deferred.promise;
}

任务3:

var saveRss = function(data) {
var deferred = when.defer();
fs.writeFile('rss.txt', data, 'utf8', function(err) {
if(err) deferred.reject(err);
deferred.resolve();
}); return deferred.promise;
}

整合:

getRssAddress('address.txt')
.then(getRss)
.then(saveRss)
.catch(function(err) {
console.log(err);
});

解释:

promise/A规范定义的“Deferred/Promise”模型就是“发布/订阅者”模型,通过Deferred对象发布事件,可以是完成resolve事件,或者是失败reject事件;通过Promise对象进行对应完成或失败的订阅。

在Promises/A规范中,每个任务都有三种状态:默认(pending)、完成(fulfilled)、失败(rejected)。

1.默认状态可以单向转移到完成状态,这个过程叫resolve,对应的方法是deferred.resolve(promiseOrValue);

2.默认状态还可以单向转移到失败状态,这个过程叫reject,对应的方法是deferred.reject(reason);

3.默认状态时,还可以通过deferred.notify(update)来宣告任务执行信息,如执行进度;

4.状态的转移是一次性的,一旦任务由初始的pending转为其他状态,就会进入到下一个任务的执行过程中。

按照上面的代码。

通过when.defer定义一个deferred对象。

var deferred = when.defer();

异步数据获取成功后,发布一个完成事件。

deferred.resolve(data);

异步数据获取失败后,发布一个失败事件。

deferred.reject(err);

并且返回Promise对象作为订阅使用。

return deferred.promise;

订阅是通过Promise对象的then方法进行完成/失败/通知的订阅。

getRssAddress('address.txt')
.then(getRss)

then有三个参数,分别是onFulfilled、onRejected、onProgress

promise.then(onFulfilled, onRejected, onProgress)

上一个任务被resolve(data),onFulfilled函数就会被触发,data作为它的参数.

上一个任务被reject(reason),那么onRejected就会被触发,收到reason。

任何时候,onFulfilled和onRejected都只有其一可以被触发,并且只触发一次。

对于处理异常,when.js也提供了极其方便的方法,then能传递错误,多个任务串行执行时,我们可以只在最后一个then定义onRejected。也可以在最后一个then的后面调用catch函数捕获任何一个任务的异常。

如此写法简单明了。

getRssAddress('address.txt')
.then(getRss)
.then(saveRss)
.catch(function(err) {
console.log(err);
});

Promise给异步编程带来了巨大的方便,可以让我们专注于单个任务的实现而不会陷入金字塔厄运,以上代码仅仅是基本使用,when.js提供的功能远远不止本文提到的这些,具体参照官方API。

node.js下when.js(Promises/A)的实践的更多相关文章

  1. Node.js(window)基础(2)——node环境下的模块,模块间调用

    参考:http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/00143450241959 ...

  2. Node.js(window)基础(1)——用cmd命令行访问某一文件夹下的js文件

    一.安装,从官网上下载安装,安装基本一直点击下一步就行.注意:node.js基于Python的,安装node.js之前电脑上要安装Python,最好是Python2.7或2.6. 二.cmd进入命令行 ...

  3. node.js 下依赖Express 实现post 4种方式提交参数

    上面这个图好有意思啊,哈哈, v8威武啊.... 在2014年的最后一天和大家分享关于node.js 如何提交4种格式的post数据. 上上一篇说到了关于http协议里定义的4种常见数据的post方法 ...

  4. npm 是node.js下带的一个包管理工具

    npm 是node.js下带的一个包管理工具          npm install -g webpack webpack是一个打包工具 gulp是一个基于流的构建工具,相对其他构件工具来说,更简洁 ...

  5. 非node环境下的vue.js 实现简单的购物车计算功能 样式请无视

    都说vue的双向数据绑定好用,自己用了下,感觉做购物车没想象中好用.自己的实现如下: <!DOCTYPE html> <html lang="en"> &l ...

  6. Node.js下的Hello World

    Node.js技术现在可谓是如火如荼,前后端都统一为Javascript的体验绝对是受到了很多人的青睐,我都后悔以前没抽时间好好学一学Javascript了. 首先,我来介绍一下Node.js.本人实 ...

  7. node.js下操作cookie

    cookie,又是cookie.工作中与cookie打交道很多次,不过时间跨度也大,每总结多一次,就加深了解多一点. cookie,一定是放在浏览器中的,用于浏览器保存一些小额度的内容.每次我们去访问 ...

  8. 基于 Angularjs&Node.js 云编辑器架构设计及开发实践

    基于 Angularjs&Node.js 云编辑器架构设计及开发实践 一.产品背景 二.总体架构 1. 前端架构 a.前端层次 b.核心基础模块设计 c.业务模块设计 2. Node.js端设 ...

  9. 转:利用node压缩、合并js,css,图片

    1.安装nodejs http://nodejs.org/ 2.安装各自的node package js我用的是UglifyJS github地址:https://github.com/mishoo/ ...

随机推荐

  1. 在此记录一下SharpGL最初创建的程序

    在此记录一下SharpGL最初创建的程序.完整工程在此. /// <summary> /// The main form class. /// </summary> publi ...

  2. java数学函数库 API(转)

    原文地址:http://www.24xuexi.com/w/2011-11-08/98206.html 首先给大家看看Math类所提供的主要方法,下面的列表给出了Math类的主要方法,如果要理解Mat ...

  3. http 各个状态码及对应的java 编程

    http的状态? 200 301 302 400 404 500 501 等等 如何编码? 其实这个是web服务器的范畴.服务器处理各个请求的时候,如果正常, 自然就是200 http://www.c ...

  4. poi 输出Excel显示内容

    在业务系统中多少回接触到Excel解析.在java开发平台下选择 Apache POI是一个非常明智的选择,POI提供非常完善API来读取或写入Microsoft Office Excel. 目前对导 ...

  5. WPF入门教程系列四——Dispatcher介绍

    一.Dispatcher介绍 微软在WPF引入了Dispatcher,那么这个Dispatcher的主要作用是什么呢? 不管是WinForm应用程序还是WPF应用程序,实际上都是一个进程,一个进程可以 ...

  6. Python中的__new__和__init__

    Python中的__new__和__init__ 写了这么多的class,现在才知道还有个__new__方法, 那么它和__init__有什么区别呢? class TestCls(): "& ...

  7. Unity3D Editor模式下批量修改prefab

    最经遇到一个需要批量修改已经做好的prefab的问题,查了一些资料最终实现了但是还是不够完美,通过学习也发现unity的编辑器功能还是非常强大的.废话不多说直接上代码: [ExecuteInEditM ...

  8. Netty学习三:线程模型

    1 Proactor和Reactor Proactor和Reactor是两种经典的多路复用I/O模型,主要用于在高并发.高吞吐量的环境中进行I/O处理. I/O多路复用机制都依赖于一个事件分发器,事件 ...

  9. MySQL(五) MySQL中的索引详讲

    序言 之前写到MySQL对表的增删改查(查询最为重要)后,就感觉MySQL就差不多学完了,没有想继续学下去的心态了,原因可能是由于别人的影响,觉得对于MySQL来说,知道了一些复杂的查询,就够了,但是 ...

  10. @@IDENTITY与SCOPE_IDENTITY()

    在一条 INSERT.SELECT INTO 或大容量复制语句完成后,@@IDENTITY 中包含语句生成的最后一个标识值.如果语句未影响任何包含标识列的表,则 @@IDENTITY 返回 NULL. ...