作者:思源科技 刘威威
# q #
## 背景 ##
### 同步api与异步api ##
nodejs中有同步api和异步api;通常情况下建议使用异步api,以提高程序的执行效率.
同步api优缺点:
- (优点)易于使用,逻辑清晰
- (缺点)使用耗时较长(如io操作)的api,程序的执行效率会非常低
异步api优缺点:
- (优点)使用耗时较长(如io操作)的api,也不会降低程序的执行效率
- (缺点)不易使用,逻辑容易乱
### 异步的问题 ###
关键在于异步api的结果如何传递
例如 读取文件:
fs.readFile(file, options, callback);//(err, data) fs.readFileSync(file, options);//data, throw Error
同步api通过函数"返回值"返回结果
异步api通过"回调函数"返回结果
回调函数存在的问题:回调嵌套
例如 顺序读取3个文件:
fs.readFile(file1, function (){ fs.readFile(file2, function () { fs.readFile(file3, function () { //回调嵌套层数多了会使程序变得复杂 }); }); });
### 解决嵌套问题 ###
解决办法就是换一种思路:回归同步api的结果返回方式,使用"返回值"将结果带回
很明显,异步的结果不会直接在"返回值"中取到,只能间接取到
Promise,这是一个概念模型,Promise对象可以携带异步api的计算结果,可以访问Promise对象得到结果(当然得到结果也会是一个异步的)
## 是什么 ##
q是Promise的一个实现,定义了若干方便易用的api.
## 有什么用 ##
解决异步嵌套的问题
除了Promise,还有其他一些为了解决异步api使用的方案,包括 async, eventproxy
缺点也比较明显,async的嵌套问题没有解决,eventproxy使用的方式更容易使逻辑变得复杂
异步api得到简化,看上去更接近同步的api
嵌套层数明显减少
## 怎么用 ##
### 生成一个Promise对象 ###
//方式1 var readFile = function (file, options) { var defer = Q.defer(); fs.readFile(file, options, function (err, data) { if (err) { defer.reject(err); } else { defer.resolve(data); } }); return defer.primise; }; //方式2 var readFile = function (file, options) { return Q.Promise(function (resolve, reject) { fs.readFile(file, options, function (err, data) { if (err) { reject(err); } else { resolve(data); } }); }); }; //方式3 Q.resolve(data); Q.reject(err);
### 访问Promise的值 ####
var promise1 = readFile('/path/to/the/data', {}); var promise2 = promise1.then(function (data) { //data 就是文件'/path/to/the/data'的内容 });
通过Promise对象的then方法就可以访问Promise对象的值,同时会生成一个新的Promise对象
//then的定义 promise.then(onFulfilled, onRejected, onProgress)
### Promise的值 ###
Promise的对象的值有两种:fulfilled和rejected
Promise的对象的值一旦确定就不再改变,且可以被反复访问
var promise1 = readFile('/path/to/the/data', {}); var promise2 = promise1.then(function (data) { //data 就是文件'/path/to/the/data'的内容 }); var promise3 = promise1.then(function (data) { //data 还是文件'/path/to/the/data'的内容, //而且'/path/to/the/data'实际只被读了1次 });
### 通过then或catch得到的新的Promise对象的值 ###
promise.then(function () { //return data; //return Q.resolve(data); //return Q.reject(new Error('error message')); //throw new Error('error message'); });
### Promise对象链式调用 ###
//假设函数f1,f2,f3,f4都是异步的且都返回Promise对象, //并且要求f1,f2,f3,f4顺序被执行 //形式1: var promise1 = f1(); var promise2 = promise1.then(function () { return f2(); }); var promise3 = promise2.then(function () { return f3(); }); var promise4 = promise3.then(function () { return f4(); }); promise4.then(function () { //f1,f2,f3,f4顺序被执行完成 }); //形式2: f1().then(function () { return f2().then(function () { return f3().then(function () { return f4().then(function () { //f1,f2,f3,f4顺序被执行完成 }); }); }); }); //形式3: f1().then(function () { return f2(); }).then(function () { return f3(); }).then(function () { return f4(); }).then(function () { //f1,f2,f3,f4顺序被执行完成 });
### Q.all(promisesArray) ###
同时进行多个异步操作
Q.all([ fs.readFile(file1, {}), fs.readFile(file2, {}) ]).then(function (results) {//[file1Data, file2Data] //当异步调用都成功的时候才执行这里 }, function () { //当存在失败的异步调用时执行这里 });
你打算打赏多少钱呢?
(微信扫一扫)