NodeJs是目前比较火的开发语言之一,现在很多公司都在开始使用NodeJs语言进行项目开发。大家都知道node最好的就行回调,但是最不好的也是回调。如果一个功能比较复杂的话就可能会会出现callback hells(回调大坑)。所以在新的node版本里面都支持es6的promise,以前要使用promise的时候,需要使用Q函数库或者bulebird(蓝鸟)函数库,后面node把promise接入了node基础版本库里面,如果需要使用promise就不需要引用这俩个函数库。如果就性能上来说的话,bulebird的执行速度会比es6的promise要快。所以在使用的时候可以看情况来选择对自己项目有利的方式。好了废话不多说了,下面就关于传统的callback写法和promise写法以及把传统的cb转换成promise,这里不使用官方的promisify,因为官方的promisify方式只能适合nodeCallback风格(1.回调函数是作为参数的最后一个;2.回调函数接收俩个参数err,data),所有改写了一下,满足不一定是nodeCallback风格的回调都能转换成promise。
1.传统的callback回调方式
let callFn = (arg1,arg2,cb)=>{//如果arg1>arg2回调正常,否则回调错误信息
setTimeout(function(){
if(arg1>arg2){
cb(null,arg1+arg2);
}else{
cb(new Error('err'),null);
}
},5000);
}
//调用
callFn(1,2,function(err,data){
if(err){
//错误处理
}else{
//正确处理
}
});
2.使用es6来写上面的功能
let promiseFn = (arg1,arg2)=>{
return new Promise((resole,reject)=>{
if(arg1>arg2){
resole(arg1+arg2);
}else{
reject(new Error('err'));
}
});
};
//调用
promiseFn(1,2).then(data=>{
//正确处理
}).catch(err=>{
//错误处理
});
通过上面俩个的对比明显promise方式更加直观,而且还不容易出现callback hells。
3.把传统的callback改写为promise
下面是转换方式
/**
* @param fn: callback回调函数
* @param _pointNum: 回调函数所在参数的位置
*/
let _promisify = (fn,_pointNum)=>{
return function(){
let args = [];
if(_pointNum){
return new Promise((resole,reject)=>{
for(var i=0,key=0;i<=arguments.length;i++){
if(i==(_pointNum-1)){
args[i] = function(err,res){
return err?reject(err):resole(res);
}
}else{
args[i] = arguments[key];
key++;
}
}
fn.apply(this,args);
});
}else{
for(var i=0;i<arguments.length;i++){
args[i] = arguments[i];
}
return new Promise((resole,reject)=>{
fn.apply(this,[].concat(args,function(err,res){
return err?reject(err):resole(res);
}))
});
}
}
};
/*下面是把上面的callback函数转换为promise函数,而且这里
的传统调法师callFn(1,2,function(){}),cb回调是最后一个
参数,所以改写成promise的时候不用传_pointNum参数*/
_promisify(callFn)(1,2)
.then(resp=>{
//成功处理
}
).catch(err=>{
//错误处理
});
/如果把callFn函数改写为下面
let callFn = (arg1,function(){},arg2)=>{}//这种形式
那么上面改为promise函数的时候为
_promisify(callFn,2)(1,2).then().catch()
如果真的想把不是nodeCallback风格的代码转换成promise格式的话,上面是把cb回调函数不是最后一个参数的形式实现,如果想要彻底实现的话,可以再加一个参数在_promisify(fn,_pointNum,_checkSuccess),其中_checkSuccess是判断返回的是成功还是失败来决定是resole(),还是reject()。这种方式就让看客们自己去实现。欢迎大家把实现方式留言在下方的评论里面,大家参考一下,,谢谢。。。。。。。