概述
为了避免线程同步问题,js采用了单线程模式,但因为单线程模式的耗时任务阻塞问题,所以将js的执行模式分为同步模式和异步模式。而回调函数可以说是js所有异步模式的根基,直接使用传统的回调方式去完成复杂的异步编程,就无法避免大量回调函数嵌套(回调地狱),所以CommonJS社区先提出了promise的规范,最后在es2015标准化。
实际上promise就是一个对象,用来表示一个异步任务结束后是成功还是失败,就像他的中文一样,是一个承诺,等待时是Pending,承诺成功(Fulfilled)会调用onFilfilled函数,承诺失败(Rejected)后调用onRejected函数。
Pending要么变为Fulfilled,要么变为Rejected,并且一经改变就会被确定下来
其实是Promise对象内部有个status属性刚开始的值是Pending,经过resolve或reject函数调用改变成Fulfilled或者Rejected了而已。
下面我们来看具体的代码
promise具体使用
1.promise基本使用
const promise = new Promise(function(resolve,reject){
if(成功的条件){
resolve(100)
}
else{
reject(new Error('promise reject'))
}
})
promise.then(function(value){
console.log(value);
} // onFilfilled函数
,function(err){
console.log(err);
}) // onRejected函数
通过 new Promise来创建一个promise实例。其中promise内部传入了两个函数resolve和reject作为执行器函数(执行器函数也就是 new Promise后面括号里的函数)的实参,.then中的第一个函数是承诺成功后的回调(onFilfilled),第二个是承诺失败后的回调(onRejected)。
我们通过调用resolve方法resolve(100)传入一个值100 表示承诺成功,状态变为Fulfilled,这个值会返回给.then方法中成功函数(onFilfilled)中的回调的参数value,反之我们通过调用reject方法reject(new Error('promise reject'))new一个Error错误 表示承诺失败,状态变为Rejected,这个错误会返回给.then方法中失败函数(onRejected)中的回调的参数err
成功的输出值
失败的输出值
2.先封装一个ajax的get请求(想了解的可以看)
function ajax(url) {
return new Promise(function(resolve,reject){
var xhr =new XMLHttpRequest()
xhr.open('GET',url)
// 转化为json对象
xhr.responseType = 'json'
// 请求完成过后执行
xhr.onload =function(){
if(this.status ==200){
//返回响应对象
resolve(this.response)
}else{
reject(new Error(this.statusText))
}
}
xhr.send()
})
}
(1)我们来调用下这个ajax请求(提前创建了本地服务器并在3007端口设置好了一个/api/user的接口)
ajax('http://127.0.0.1:3007/api/user').then(function(res){
console.log('成功');
console.log(res);
},function(err){
console.log('失败')
console.log(err)
})
这是返回的结果
我们再次调用一个不存在的接口
ajax('http://127.0.0.1:3007/api/sss').then(function(res){
console.log('成功');
console.log(res);
},function(err){
console.log('失败')
console.log(err)
})
返回了
3.链式调用
ajax('http://127.0.0.1:3007/api/user')
.then(function(res){ // 每次.then都会返回一个新的promise对象,可以继续调用.then实现链式调用
console.log('成功');
console.log(res);
return 100
// return的值作为下次成功函数的实参res
}).then(function(res){
console.log(res);
// 没有返回值则是undefined
}).then(function(res){
console.log(res);
}).then(function(res){
throw new Error('错误')
console.log(res);
})
// 可以用.catch 作为失败函数的回调,不写则会一直传递下去
.catch(function(err){
console.log('no');
console.log(err);
})
我们来看控制台输出结果
其实.catch(fn)等同于.then(undefined,fn)
4.promise的一些其他静态方法
(1)Promise.all()
可以将多个Promise对象封装成一个Promise对象
const request1 = ajax('/api/user.json')
const request2 = ajax('/api/login.json')
Promise.all([request1,request2]).then(value =>{
console.log(value);
})
输出结果
1. 只有当request1和request2的状态为成功(fulfilled)时 Promise.all()的状态才会变为成功(fulfilled),并将request1和request2的返回值组成一个新的返回值数组,传递给.then中成功的回调函数
2.两者有一个状态为失败(rejected),则新的Promise的状态为失败(rejected)
(2)Promise.race()
const aaa = new Promise((resolve,reject)=>{
setTimeout(()=>{resolve('我的状态是成功,我先改变')},200)
})
const eee = new Promise((resolve,reject)=>{
setTimeout(()=>{reject(new Error('nonono'))},500)
})
Promise.race([request1,eee]).then(function(value){
console.log(value);
}).catch(err =>{
console.log(err);
})
输出结果
跟all类似,可以将多个Promise对象封装成一个Promise对象,但是ta的状态和返回值是根据多个Promise中率先发生状态改变的那个Promise的状态和值。
(3)Promise.resolve()与Promise.reject()
Promise.resolve(111) 等同与 new Promise((reslove,reject)=>{reslove(111)})
Promise.reject('错误') 等同与 new Promise((reslove,reject)=>{reject('错误')})