在javascript开发过程中,代码是单线程执行的,同步操作,彼此之间不会等待,这可以说是它的优势,但是也有它的弊端,如一些网络操作,浏览器事件,文件等操作等,都必须异步执行,针对这些情况,起初的操作都是使用回调函数实现。
实现方式如下(伪代码):
function One(callback) {
if (success) {
callback(err, result);
} else {
callback(err, null);
}
}
One(function (err, result) {
//执行完One函数内的内容,成功的结果回调回来向下执行
})
上述代码只是一层级回调,如果代码复杂后,会出现多层级的回调,代码可读性也会很差,那有没有一种方式,不用考虑里面的内容,直接根据结果成功还是失败执行下面的代码呢?有的,Promise(承诺),在ES6中对Promise进行了同意的规范。
注意Promise在某一时刻只能处于一种状态
Promise的状态改变,状态只能由pending转换为rejected或者rejected,一旦状态改变完成后将无法改变(不可逆性)
创建Promise需要用到Promise的构造函数来实现,代码如下:
var promise=new Promise(function(resolve,reject){
// ...some async code
if(/* 一些异步操作成功*/)
{
resolve(value);
}else
{
reject(error);
}
})
代码分析:
promise.then(function(value){
//success
},function(error){
});
代码分析:
promise.then(function (data){
//success
})
.catch(function(error){
//error
})
//之前创建promise操作后
promise.then(function(value){
conlose.log(value); //有值
}.then(function(value)
{
conlose.log(value); //未定义
});
代码分析:
转换的对象是一个常量或者不具备状态的语句,转换后的对象自动处于resolve状态。转换的后的结果和原来一样
var promise =Promise.resolve("hello world");
promise.then(function(result){
console.log(result); //输出结果 hello world
})
转换的对象如果直接是一个异步方法,不可以这么使用。
代码如下
promise.all(
//一系列promise操作
).then(function(results){
}).catch(function(error){
});
代码分析:
项目开发中promise的应用代码:
Promise.all([
self.count({phoneNumber: mobile, createdOn: {$gt: hour}}),
self.count({ip: ip, createdOn: {$gt: hour}})
]).then(function (results) {
if (results[0] >= 5) {
return callback({code: -1, message: '短信发送频率过快,每手机号1小时内只能发送5次'});
}
if (results[1] >= 5) {
return callback({code: -1, message: '短信发送频率过快,每IP1小时内只能发送5次'});
}
let code = {
phoneNumber: mobile,
code: tool.makeRandomStr(4, 1).toLowerCase(),
createdOn: new Date(),
expiredOn: new Date(new Date().getTime() + (20 * 60 * 1000)), //20分钟失效
ip: ip,
isUsed: false
};
self.create(code, function (err, newCode) {
if (newCode) {
sms.sendSMS(mobile, newCode.code, 'ali', function (err, body) {
console.log(body);
if (err)
console.log("短信验证码发送失败:", err);
});
callback({code: 0, message: "验证码已经发送"});
} else {
callback({code: -1, message: "验证码发送失败,请重试"});
}
})
})
项目开发过程中使用promise.all的代码,当时是为了实现短信验证码发送前的校验功能。all中的两个promise,第一个是统计时间内该手机号发送验证码数量;第二个是统计时间内该ip发送验证码的数量。
注意事项在上面原理讲解过程中,基本都提到过,只是重要的事情多说两遍。
Promise的讲解就到这里,但是大家在开发过程中,会发现有些时候多次操作异步会出现很多层级的调用,也就是
promise.then(...)
.then(...)
.then(...)
这种情况,代码虽然看起来会比callback的回调简介和规范了很多,但是还是感觉一些复杂,有没有更好的解决办法呢?请看下一篇博客
回调的终极使用--async和await的讲解