当前位置: 首页 > 工具软件 > node-promise > 使用案例 >

node.js promise 流程控制

楚昀
2023-12-01

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;
}

then

链式用q的then串联,链式实现了函数值依次传递。

read1('begin').then(read2).then(read3).done(function(data) {}, function(err) {});

Q.all

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);
});

Q.allSettled

函数数组方式,当函数中出现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) {

});

process

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();



 类似资料: