ECMAscript 6 原生提供了 Promise 对象。
Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。
Promise 对象代表一个异步操作,有三种状态:
pending: 进行中
resolved: (又称 fulfilled ) 操作成功完成。
rejected: 操作失败。
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。Promise 对象的状态改变,只有两种可能:从 pending 变为 resolved 和从 pending 变为 Rejected。
promise对象还有一个比较常用的then方法,用来执行回调函数,then方法接受两个参数,第一个是成功的resolved的回调,另一个是失败rejected的回调,第二个失败的回调参数可选。如果只接受了一个参数,那么就需要用catch来接收rejected的回调。
创建一个Promise实例:
var p=()=>{
return new Promise((resolve,reject)=>{
if(true){ //添加判断条件
resolve('成功')
}else{
reject('失败')
}
})
}
//
p()
.then((data)=>{
console.log(data) //成功
},(error)=>{
console.log(error)
}) //这里的then接受两个参数,第一个是resolve的回调,第二个则是reject的回调
p()
.then((data)=>{
console.log(data) //成功
})
.catch((error)=>{
console.log(error)
})//这个then只接收了一个参数,就是resolve的回调,用catch来接收reject
Promise链式调用
在then方法里面返回Promise对象,就可以实现链式调用。
1、先看看全部设置为 resolve 的例子
var p1=()=>{
return new Promise((resolve,reject)=>{
resolve('执行p1成功')
})
}
var p2=(data)=>{
return new Promise((resolve,reject)=>{
console.log(data)
resolve('执行p2成功')
})
}
var p3=(data)=>{
return new Promise((resolve,reject)=>{
console.log(data)
resolve('执行p3成功')
})
}
p1().then(p2).then(p3).then((data)=>{
console.log(data)
}).catch((error)=>{
console.log(error)
})
//结果输出为
//执行p1成功
//执行p2成功
//执行p3成功
2、部分设置为reject的例子
var p1=()=>{
return new Promise((resolve,reject)=>{
resolve('执行p1成功')
})
}
var p2=(data)=>{
return new Promise((resolve,reject)=>{
console.log(data)
reject('执行p2失败') //设置为reject
})
}
var p3=(data)=>{
return new Promise((resolve,reject)=>{
console.log(data)
resolve('执行p3成功')
})
}
p1().then(p2).then(p3).then((data)=>{
console.log(data)
}).catch((error)=>{
console.log(error)
})
//输出结果
//执行p1成功
//执行p2失败
在执行catch回调之后就不会在之后的then回调,
上述例子中p2返回reject就不会在执行then(p3)了
then的第二个参数onRejected和catch的用法介绍
虽然这两个方法都可以用来捕获错误,不过then的onRejected方法有个很明显的缺陷,就是当Promise的状态为resolve或者reject之后再抛出错误是不能够捕获到的。因为 Promise 的状态一旦改变,就永久保持该状态,不会再变了
new Promise((resolve, reject)=>{
resolve('ok');
throw new Error('test');
}).then((value)=>{ console.log(value) },
(error)=>{console.log(error)}) //ok 不能捕获异常
Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
在链式调用中采用then的第二个参数来捕获异常
function taskA() {
console.log("Task A");
throw new Error('test')
}
function taskB() {
console.log("Task B");
}
function onRejected(error) {
console.log("Catch Error: ", error);
}
Promise.resolve()
.then(taskA,()=>onRejected)
.then(taskB,()=>onRejected) //Task A 没有捕获到异常,但是也不会输入Task B
//Promise 内部有未捕获的错误,会直接终止进程
Promise.resolve()
.then(taskA)
.then(taskB)
.catch(onRejected) //Task 同时输出异常
因此在Promise的链式调用中,最好不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。
Promise.all
Promise.all 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个数组,而失败的时候则返回最先被reject的值。
var p1=()=>{
return new Promise((resolve,reject)=>{
resolve('执行p1成功')
})
}
var p2=()=>{
return new Promise((resolve,reject)=>{
reject('执行p2失败') //设置为reject
})
}
var p3=()=>{
return new Promise((resolve,reject)=>{
resolve('执行p3成功')
})
}
var p11=p1()
var p33=p3()
Promise.all([p11,p33]).then((results)=>{
console.log(results) //返回结果仍是["执行p1成功", "执行p3成功"]
}).catch((error)=>{
console.log(error)
})
var p22=p2();
Promise.all([p11,p22,p33]).then((results)=>{
console.log(results) //返回结果为执行p2失败
}).catch((error)=>{
console.log(error)
})
Promise.race
Promise.race 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。不过它的返回值取决与第一个改变状态的实例的返回值。通俗的说就是哪个实例执行快就返回对应实例的返回值(不管是resolve还是reject状态)。
var p1=(time)=>{
return new Promise((resolve,reject)=>{
setTimeout(() => {
resolve('执行p1成功')
}, time);
})
}
var p2=(time)=>{
return new Promise((resolve,reject)=>{
setTimeout(() => {
reject('执行p2失败')
}, time);
})
}
//p1设置为3后执行,p2设置为2s后执行
Promise.race([p1(3000),p2(2000)]).then((results)=>{
console.log(results)
}).catch((error)=>{
console.log(error)
})
//输出结果为 执行p2失败
来看一下链式调用的执行顺序:
setTimeout(() => {
console.log('last')
}, 0);
Promise.resolve().then(()=>{console.log('resolve')})
new Promise((resolve,reject)=>{
console.log('pro1')
resolve()
}).then(()=>{
console.log('then11')
new Promise((resolve,reject)=>{
console.log('pro2')
resolve()
}).then(()=>{
console.log('then21')
}).then(()=>{
console.log('then22')
})
}).then(()=>{
console.log('then12')
})
// pro1 resolve then11 pro2 then21 then12 then22 last
在同一个Promise对象中,如果存在多个then回调,以第一个回调完成为主,当第一个then执行之后,整个Promise对象的状态就已经确认了(resolve或者reject)。上面的代码中内部的Promise对象 ,执行完console.log(‘then21’)就进行如resolve状态,同时外部的Promise也随着内部的输出而进行了resolve状态,因此才会继续执行外部的第二个then回调。查看事件循环