Promise
Promise 是一个对象, 可以从它获取异步操作的消息。当Promise的状态改变为resolve
或reject
时,再对Promise对象添加回调函数,也会立即得到这个结果。Promise 的状态一旦被改变,就无法再变。
var promise = new Promise((resolve, reject) => {
// some code
if(/*异步操作成功*/) {
resolve()
} else {
reject()
}
// resolve 和 reject 函数的参数会传递给回调函数
})
// then 方法指定的回调函数会在当前脚本的所有同步任务执行完成后才会执行
promise.then(function(value){
// success
}, function(error){
// failure
})
使用 Promise 包装图片加载的异步操作
function loadImageAsync(url) {
return new Promise(function(resolve, reject) {
var image = new Image()
image.onload = function() {
resolve(image)
}
image.onerror = function(){
reject(new Error('Could not load image at ' + url))
}
image.src = url
})
}
用Promise 对象实现ajax操作的
var promisfy = function(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest()
xhr.open('GET', url)
xhr.onreadystatechange = function() {
if (this.readyState !== 4) return
if (this.status === 200) {
resolve(this.response)
} else {
reject(new Error(this.statusText))
}
}
})
xhr.responseType = 'json'
xhr.setRequestHeader('Accept', 'application/json')
xhr.send()
}
promisfy('https://get?p=1').then(function(value){
console.log(json)
}, function(error){
console.error(error)
})
then 方法第一个参数是 resolve 状态的回调函数,第二个参数可选,是 reject 状态的回调函数。then 方法返回的是一个新的 Promise 实例,因此可以使用链式写法。
catch 方法,返回的是一个 Promise 实例,相当于 .then(null, rejection) 的别名,如果异步操作抛出错误,状态会变成 rejected,然后调用 catch 方法指定的回调函数处理这个错误,then 方法指定的回调函数在运行中抛出错误,也会被 catch 捕获。Promise 的状态具有冒泡性质,错误(then / catch 中)会一直向后传递,直到被捕获,被捕获后不会再被后面的 catch 捕获。
如果没有使用 catch 方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,也无法被 try catch 捕获。
node 中的 unhandledRejection 事件,专门监听未捕获的 reject 错误。
process.on('unhandledRejection', function(err, p) {
// err 参数是错误对象, p 是报错的 promise 实例, 用于了解发生错误的环境信息
})
Promise.all
Promise.all 用于将多个 Promise 实例包装成一个新的 Promise 实例,接收的成员必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
var p = Promise.all([p1, p2, p3])
- 只有p1, p2 ,p3的状态都变成 fullfilled,p的状态才会变成 fulfilled,此时p1, p2, p3的返回值组成一个数组,传递给 p 的回调函数。
- 只要p1, p2, p3的值有一个 rejected, p的状态就变成rejected,此时第一个被 reject 的实例的返回值会传递给 p 的回调函数。
const p1 = new Promise((resolve, reject) => {
resolve('holly')
})
.then(res => res)
.catch(e => e)
const p2 = new Promise((resolve, reject) => {
throw new Error('get error')
})
.then(res => res)
// .catch(e => e) 注释的时候走入 catch 逻辑,否则走入 then逻辑
Promise.all([p1, p2])
.then(res => {
console.log(res)
})
.catch(e => {
console.log(e)
})
如果作为参数的 Promise 实例自身定义了 catch 方法,它被reject 时不会触发 Promise.all 里面的 catch 方法。
Promise.race
Promise.race 方法将多个 Promise 实例包装成一个新的 Promise 实例。
var p = Promise.race([p1, p2, p3])
p1,p2,p3中有一个实例率先改变状态,p的状态就跟着改变,先改变的promise实例的返回值传递给p的回调函数。
Promise.finally
finally
方法用于指定不管 Promise对象最后状态如何都会执行的操作,接收一个普通回调函数作为参数,该函数不管怎样都会执行。
针对同时发起两个请求,需要知道两个请求的请求结果,不管请求成功还是失败都要进行操作的场景,可以使用 Promise.all 和 finally 实现
var p1 = new Promise((resolve, reject) => {
resolve('holly')
})
.then(res => {
p1.succ = true
})
.catch(e => e)
var p2 = new Promise((resolve, reject) => {
throw new Error('get error')
})
.then(res => res)
.catch(e => {
p2.fail = true
})
Promise.all([p1, p2])
.then(res => {
console.log(res)
})
.catch(e => {
console.log(e)
})
.finally(function(){
console.log('finally')
console.log(p1.succ)
console.log(p2.fail)
})