nodejs promise for q.js

摘要: q.js在nodejs里是一个非常流行的promise库,支持浏览器端使用,详情请点击这里
q.js跟async要解决的问题差不多,都是解决回调函数的嵌套问题,避免嵌套层级太深导致一系列的问题.只是q.js是以promise来实现回调的扁平化,而async则是通过流程来控制多个异步回调的处理.

q.js在nodejs里是一个非常流行的promise库,支持浏览器端使用,详情请点击这里

q.js跟async要解决的问题差不多,都是解决回调函数的嵌套问题,避免嵌套层级太深导致一系列的问题.只是q.js是以promise来实现回调的扁平化,而async则是通过流程来控制多个异步回调的处理.

q.js的所有方法操作的对象都得是一个promise对象,下面来说说怎么用q来创建promise对象

下面所有实例统一在nodejs环境里执行,请执行下面命令安装q.js,然后引用它

npm install q --save var q = require('q'),
    fs = require('fs');

下面会用到文件模块,所以也要引用

创建promise对象

q.fcall 传递给此方法一个返回值的函数或者一个defer实例,将会创建一个promise对象

var promise = q.fcall(function(){
    return [10, 20];
});

var promise1 = q.fcall(function(){
    var deferred = q.defer();
    fs.readFile('../data/file2.txt', 'utf8', deferred.makeNodeResolver());
    return deferred.promise;
});

q.defer 通过延迟对象来创建promise对象

var getFile = function(){
    var deferred = q.defer();
    fs.readFile('../data/file.txt', 'utf8', function(err, content){
        if(err){
            deferred.reject(new Error(err));
        }else{
            deferred.resolve(content);
        }
    });
    return deferred.promise;
}

q.promise 传递此方法一个函数来创建promise对象

var getFilePromise = function(){
    return q.promise(function(resolve, reject, notify){
        fs.readFile('../data/file.txt', 'utf8', function(err, content){
            if(err){
                reject(new Error(err));
            }else{
                resolve(content);
            }
        });
    })
}

说完了创建promise对象,然后我们来看看怎么使用这些对象吧

使用promise对象

最简单的使用方法就是直接使用then方法,传入一个成功回调与一个异常回调

// fcall创建的promise


promise.then(function(msg){
    console.log(msg);
}, function(err){
    // do stuff
});



// q.defer创建的promise
getFile().then(function(msg){
    console.log(msg);
}, function(err){
    // do stuff
})

// q.promise创建的promise中q.defer使用一样
q.all 使用此方法可以保证执行多个异步方法之后执行回调
q.all([promise, promise1]).then(function(msg){
    console.log('normal', msg);
}, function(err){
    console.log(err);
})

上面的q.all方法成功返回的结果会返回一个包含所有异步方法结果的数组,出现一个异步方法异常则执行错误回调方法.

注意q.all 里的promise数组支持不带延迟对象以及延迟对象

q.when 使用此方法执行不带延迟对象以及延迟对象promise,不支持传递数组内带延迟对象

q.when(promise1, function(msg){
    log('when' + msg);
},function(err){
    console.log(err);
})
q.when(promise, function(msg){
    log('when' + msg);
},function(err){
    console.log(err);
})

q.when([promise, promise], function(msg){
    log('when' + msg);
},function(err){
    console.log(err);
})

返回的结果处理跟q.all一样

注意q.when 不支持数组内传递延迟对象

q.nfcall | q.nfapply 这两方法是对nodejs里异步方法的适配,不用写上面promise对象定义里的resolve及reject等

q.nfcall(fs.readFile, '../data/file.txt', 'utf8').then(function(msg){
    console.log('nfcall', msg);
})

q.nfapply(fs.readFile, ['../data/file.txt', 'utf8']).then(function(msg){
    console.log('nfapply', msg);
})

其实nfcall = node function call, nfapply = node function apply,传递的传递参考call与apply方法,回调处理跟上面的一样

当回调函数内出现异常时,回调异常函数是catch不到的,这里q提供了一个fail方法

var getFileHandy = function(){
    var deferred = q.defer();
    fs.readFile('../data/file1.txt', 'utf8', deferred.makeNodeResolver());
    return deferred.promise;
}
getFileHandy().then(function(msg){
    console.log(msg);
    throw new Error('demo exception');
}).fail(function(err){
    // 此处可以catch 所有的异常
    console.log(err);
});

以上都是单一的异步方法调用,下面说说q里的链式调用

promise1.then(function(msg){
    return getFile();
}).
then(function(msg){
    return getFileHandy()
    .then(function(data){
        return getFilePromise();
    })
    .then(function(content){
        console.log('>>' + content);
        throw new Error('haha error!');
    });
}).
fail(function(err){
    console.log('err>>' + err);
});

所谓的链式调用就是在成功回调内返回一个新的promise对象,假如之后的回调不需要获取闭包内容的话,可以直接返回,否则可以接着写then方法调用

总结
q.js是一个非常好用的promise实现,前后端都可以用,像ng里就有一个$q的实现,强烈推荐大家使用这个.

实例

var Q = require('q');

//用Q整合的函数都是调用mongoose的,返回查询表的结果或者创建新表
var findUserByNickname = Q.nfbind(UserProfileModel.findUserByNickname.bind(UserProfileModel));
//Q.nfbind 和Q.denodeify是一个东西,同名而已。

//使用 Q.defer()自定义合法返回的内容,注意要在回调函数外使用return deferred.promise的语法
var nameFind = function(exist){
 var deferred = Q.defer();
    if (exist) {
        message = "用户名重复";
        deferred.resolve(1);
        return deferred.promise;
    }else{
        UserProfileModel.findUserByEmail(email,function(err,user){
            if (user) {
                deferred.resolve(1);
                message = "邮箱重复";
            }else {
                deferred.resolve(0);
            };
        });
        return deferred.promise;
    };
}

var emailFind = function(exist){
    var deferred = Q.defer();
    if (exist==0){
        UserProfileModel.createSimpleUser(user_nickname,user_realname,email,password,userid,function(err,user){
            deferred.resolve(user);
            message = "注册成功";
        });
    return deferred.promise;
    }else{
        deferred.resolve(1);
        return deferred.promise;
    }
}

//最后直接调用函数的实例,function error自动收集error。
findUserByNickname(user_nickname)
.then(nameFind)
.then(emailFind)
.then(
function(data){
    res.send(message);
},function(error){
    res.sendError("注册失败");
    console.log(error);
});
//Q 的使用一
var preadFile = function(file){
    var deferred = Q.defer();//
    fs.readFile(file, "utf8",function(err,data){            
        if(!err){
            deferred.resolve(data);//成功返回的数据
        }else{
            deferred.reject(err);//失败返回的错误信息
        }           
    });
    return deferred.promise;//必须返回这个
}

preadFile("foo.json").then(function (data) {//then方法有两个参数(成功回调,失败回调)
    console.log(data);
}, function (error) {      
    console.error(error);
});


//Q 的 all组合方法(你可以把一系列promises到整个promises中)
function test(value) {
    return Q.delay(value, 1000);//延迟1秒
}

Q.all([
    test(10),//执行三个函数
    test(20),
    test(30)
])
.spread(function (x, y,z) {//三个函数返回的三个值
    console.log(x, y,z);
    return x+y+z;
})
.done(function(str){//完成前面的后执行
    console.log(str)
});
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值