概述
Promise是javascript异步操作统一解决方案,它在异步操作和回调函数中起到中介作用,promise能够让异步操作写起来不必一层一层嵌套回调函数,增加代码的可读性。
传统的回调函数
由于回调函数是作为参数传入另外一个函数中,而异步操作的结果一般为这个回调函数的参数,假设我需要在f1执行后调用f2,传统的写法会是这样的
function f1(fn){
fn()
}
function f2(x){
console.log(x)
}
f1(f2('hello')) //hello
但是一旦有些任务需要多层嵌套,代码就会写成
step1(function (value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) {
// ...
});
});
});
});
而使用promise就极为清晰,它使用返回实例对象的then方法,增加代码的可读性
let promise =new Promise(step1)
promise.then(step2).then(step3)
Promise构造函数
JS提供原生写法,来生成Promise实例
let promise=new Promise((resolve,reject)=>{
if('操作成功'){
resolve()
}else{
reject()}
})
Promise构造函数接收一个函数为参数,函数中又接收两个函数作为参数,当异步操作成功时,执行resolve函数,不成功则执行reject。
实例状态
Promise对象根据自身的状态来控制异步操作,Promise实例有三种状态:
1、异步操作未完成(pending)
2、异步操作成功(fulfilled)
3、异步操作失败(rejected)
这三种状态只有两种状态转化结果:
- 从未完成到成功
- 从未完成到失败
一旦状态发生变化,就不再改变,这也是Promise的由来,意味着“承诺”
因此,Promise的结果有两种,成功则返回一个值,并将状态改成fulfilled
失败则抛出一个error,状态改成rejected
resolve和reject函数
resolve函数的作用是,将Promise实例的状态从“未完成”变为“成功”(即从pending变为fulfilled),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。
reject函数的作用是,将Promise实例的状态从“未完成”变为“失败”(即从pending变为rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
let a=new Promise((resolve,reject)=>{
setTimeout(reject,1000)
})
上面的代码是1秒钟过后,执行reject函数,此时实例对象a的状态会发生变化
// a
[[PromiseState]]: "rejected"
[[PromiseResult]]: undefined
使用promise封装ajax
function ajax(method, url, data) {
const request = new XMLHttpRequest()
return new promise((resolve, reject) => {
request.open(method, url)
request.onreadystatechange = () => {
if (request.readyState === 4 && request.status === 200) {
const obj = JSON.parse(request.response)
resolve(obj)
} else {
reject(request.status)
}
}
request.send(data)
})
}
Promise.prototype.then()
Promise 实例的then方法,用来添加回调函数。
then方法可以接受两个回调函数,第一个是异步操作成功时(变为fulfilled状态)的回调函数,第二个是异步操作失败(变为rejected)时的回调函数(该参数可以省略)。一旦状态改变,就调用相应的回调函数。
var p=new Promise((resolve,reject)=>{
resolve('我成功了')
})
p.then((data)=>{console.log(data)},(data)=>{console.log('失败'+data)})
//我成功了
上面的代码返回一个直接执行Promise后面的函数,并且在函数中继续运行resolve函数,运行后返回一个promise对象给p,在p的基础上再继续调用回调函数,由于此时p的状态被resolve函数改变成fulfilled,所以会执行then后的第一个函数。
then的链式操作
每次then之后都会返回一个新的Promise对象,所以then是可以链式操作的
p1
.then(step1)
.then(step2)
.then(step3)
.then(
console.log,
console.error
);
上面代码中,p1后面有四个then,意味依次有四个回调函数。只要前一步的状态变为fulfilled,就会依次执行紧跟在后面的回调函数。
最后一个then方法,回调函数是console.log和console.error,用法上有一点重要的区别。console.log只显示step3的返回值,而console.error可以显示p1、step1、step2、step3之中任意一个发生的错误。举例来说,如果step1的状态变为rejected,那么step2和step3都不会执行了(因为它们是resolved的回调函数)。Promise 开始寻找,接下来第一个为rejected的回调函数,在上面代码中是console.error。这就是说,Promise 对象的报错具有传递性。