node.js下when.js(Promises/A)的实践
来源:互联网 发布:chart.js 环形的粗细 编辑:程序博客网 时间:2024/04/29 23:00
假设一个业务场景:
通过rss地址,获取rss并保存于文件,rss地址保存于文件中。
完成该场景的业务需要完成3个任务:
1.从文件中读取rss地址。
2.获取rss。
3.保存于文件。
最后将这三个任务进行整合。
准备:
存放rss地址的文件,address.txt。
http://programmer.csdn.net/rss_programmer.html
</pre></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; font-family: 微软雅黑; font-size: 13.92px; line-height: 20.88px;"><span style="margin: 0px; padding: 0px; font-family: 'Microsoft YaHei';"></span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; font-family: 微软雅黑; font-size: 13.92px; line-height: 20.88px;"><span style="margin: 0px; padding: 0px; font-family: 'Microsoft YaHei';"></span></p>任务1:读取rss地址文件的内容并通过callback返回。<p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; font-family: 微软雅黑; font-size: 13.92px; line-height: 20.88px;"><span style="margin: 0px; padding: 0px; font-family: 'Microsoft YaHei';"></span></p><p style="margin: 10px auto; padding-top: 0px; padding-bottom: 0px; font-family: 微软雅黑; font-size: 13.92px; line-height: 20.88px;"><span style="margin: 0px; padding: 0px; font-family: 'Microsoft YaHei';"></span><pre name="code" class="javascript">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)的实践
- Node.js : Using Promises with mongoosejs
- [转]JavaScript/Node.JS 中的 Promises
- Node.js的实践总结
- node.js下LDAP查询实践
- Node.js实践
- node.js入门实践
- Node.js编写CLI的实践
- 基于promise.js实现nodejs的promises库
- 十个书写Node.js REST API的最佳实践(下)
- 《Node.js在CLI下的工程化体系实践》成都OSC源创会分享总结
- node.js async实践分享
- Node.js实践第一天
- UglifyJS在Node.js下的安装
- Windows平台下的Node.js安装
- cocos2d-js下node的暂停schedule
- WINDOW下,node.js的安装
- Linux下Node.js的安装配置
- 闹钟广播的写法
- Exception in thread "main" java.lang.NoClassDefFoundError: aa (wrong name:xxxxx)
- Android:Material Design(六) 使用Drawable
- windows系统下,django1.8+python3.5使用pymysql链接 mysql数据库
- Hibernate3.6 入门(笔记一):简单应用_配置
- node.js下when.js(Promises/A)的实践
- NFS奇怪问题1 - NFS无法工作,服务重启失败,挂载目录变成问号。
- cocos2d_x游戏开发第一天(上)
- Android Notification的常规使用方法笔记
- zy2
- xml+xsl + css 笔记
- jquery cookie控制过期时间解决方案
- 颜色分类
- 用css 添加鼠标悬浮出现各式样的图形