promise 一个标准,Promise也已经纳入了ES6,而且高版本的chrome、firefox浏览器都已经原生实现了Promise,它描述了异步调用的返回结果,包括正确返回结果和错误处理,可以解耦异步调用中的复杂嵌套问题。关于详细的说明文档可以参考 Promises/A+ 。目前实现 promise 标准的模块有很多,如 Q 、 bluebird 和 Deferred ,下面我们以 Q 为例,介绍一下 promise 在 nodejs 中的使用方法。
有这么一个场景:有三个文件file1、file2、file3,按照先后顺序依次读取,然后拼接起来(或者说一个函数用到另外一个函数的值)。
传统通过回调嵌套方式实现同步,来保障拼接的字符串不会乱。
var str = 'begin'; fs.readFile('file1.txt', function(err, data1) { str += data1; fs.readFile('file2.txt', function(err, data2) { str += data2; fs.readFile('file3.txt', function(err, data3) { str += data3; }); }); });我们现在采用基于promise规范的Q
安装:npm install q
引入项目:var Q = require(‘q‘);
首先将上面3层嵌套代码解耦和,并用Q.deferred构建
var Q = require('q'), fs = require('fs'); var str = 'begin'; function read1(data) { var deferred = Q.defer(); fs.readFile('file1.txt', function(err, data1) { if (err) { deferred.reject(err); } else { deferred.resolve(data += '~' + data1); } }); return deferred.promise; } function read2(data) { var deferred = Q.defer(); fs.readFile('file2.txt', function(err, data2) { if (err) { deferred.reject(err); } else { deferred.resolve(data += '~' + data2); } }); return deferred.promise; } function read3(data) { var deferred = Q.defer(); fs.readFile('file3.txt', function(err, data3) { if (err) { deferred.reject(err); } else { deferred.resolve(data += '~' + data3); } }); return deferred.promise; }
链式用q的then串联,链式实现了函数值依次传递。
read1('begin').then(read2).then(read3).done(function(data) {}, function(err) {});
Q.all可以传入数组,数组含有n个函数,数组内的函数是异步执行的,spread收集每个函数的返回值
Q.all([ read1(), read2(), read3() ]).spread(function(data1, data2, data3) { console.log(data1, data2, data3); });或者
Q.spread([ read1(), read2(), read3() ]).spread(function(data1, data2, data3) { console.log(data1, data2, data3); });
函数数组方式,当函数中出现err(deferred.reject)或者没有返回deferred.resolve,done、spread不会返回值。Q.allSettled是用于保障函数出现异常时候,不会中断其它函数运行,最后统一返回值。
我们测试一下,让read1只返回deferred.reject
function read1(data) { var deferred = Q.defer(); fs.readFile('file1.txt', function(err, data1) { // if (err) { deferred.reject(err); // } else { // deferred.resolve(data += '~' + data1); // } }); return deferred.promise; }执行
Q.allSettled([ read1(), read2(), read3() ]).spread(function(data1, data2, data3) { console.log(data1, data2, data3); }); 或者 Q.allSettled([ read1(), read2(), read3() ]).then(function (results) { results.forEach(function (result) { if (result.state === "fulfilled") { var value = result.value; } else { var reason = result.reason; } }); });结果
{ state: 'rejected', reason: null } { state: 'fulfilled', value: 'undefined~love ' } { state: 'fulfilled', value: 'undefined~you' }state: ‘rejected‘ 标识运行出现错误;state:‘fulfilled‘ 完成;reason:null 打印err内容;value:‘xxx‘ 返回值
如果你有一组函数并且需要顺序执行,可以通过手动的then方式
read1.then(read2).then(read3));
var funcs = [read1, read2, read3]; var result = Q('begin');//定义一个初始值begin funcs.forEach(function(f) { result = result.then(f);//遍历传参 });
var funcs = [read1, read2, read3]; funcs.reduce(function(soFar, f) { return soFar.then(f); }, Q('begin'));
使用fail函数
Q.allSettled([ read1(), read2(), read3() ]).fail(function(error) { });
Promise有个then方法,then方法可以接受3个函数作为参数。前两个函数对应Promise的两种状态的回调函数fulfiled 和 rejected,第三个函数用于处理进度信息。
uploadFile() .then(function () { // Success uploading the file }, function (err) { // There was an error, and we get the reason for error }, function (progress) { // We get notified of the upload's progress as it is executed });
uploadFile().progress(function (progress) { // We get notified of the upload's progress });
结束部分引用了:http://blog.csdn.net/boyzhoulin/article/details/40592837的内容,如下
通常,对于一个promise链,有两种结束的方式。第一种方式是返回最后一个promise
如 return foo().then(bar);
第二种方式就是通过done来结束promise链
如 foo().then(bar).done()
为什么需要通过done来结束一个promise链呢? 如果在我们的链中有错误没有被处理,那么在一个正确结束的promise链中,这个没被处理的错误会通过异常抛出。
var Q = require('q'); /** *@private */ function getPromise(msg, timeout, opt) { var defer = Q.defer(); setTimeout(function() { console.log(msg); if (opt) defer.reject(msg); else defer.resolve(msg); }, timeout); return defer.promise; } /** *没有用done()结束的promise链 *由于getPromse('2',2000,'opt')返回rejected, getPromise('3',1000)就没有执行 *然后这个异常并没有任何提醒,是一个潜在的bug */ getPromise('1', 3000) .then(function() { return getPromise('2', 2000, 'opt') }) .then(function() { return getPromise('3', 1000) }); /** *用done()结束的promise链 *有异常抛出 */ getPromise('1', 3000) .then(function() { return getPromise('2', 2000, 'opt') }) .then(function() { return getPromise('3', 1000) }) .done();
原文:http://blog.csdn.net/shmnh/article/details/43869393