q使用

2016-02-27 17:36:29

作者:思源科技  刘威威

# 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 () {
        //当存在失败的异步调用时执行这里
    });


你打算打赏多少钱呢?

打赏
(微信扫一扫)