Promise是一种异步编程的解决方案,比传统的回调函数更强大更优雅,结构更清晰
Promise是一个容器,里面保存着某个未来即将发生的事情,通常是一个异步操作,它有三种状态,pedding(进行中)、resolved(已成功)、rejected(已失败),只有异步操作的结果才能决定当前状态;一旦状态改变就不会再变了,而且只有两种变化的方式,从pedding→resolved或从pedding→rejected
在ES6中规定Promise是构造函数,用来生成一个promise对象,构造函数的参数是一个函数,这个函数有两个参数:resolve和reject,这两个参数也是函数,异步操作成功时(pedding→resolved)调用resolve(),操作失败时(pedding→rejected)调用reject()
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数
简单例子:
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'done')
})
}
timeout(100).then((value) => {
console.log(value)
})
Promise新建后会立即执行,然后then指定的回调函数会在当前同步任务执行完再执行
let promise = new Promise(function(resolve, reject) {
console.log('Promise')
resolve()
})
promise.then(function() {
console.log('resolved.')
})
console.log('Hi!')
// Promise
// Hi!
// resolved
用Promise实现 Ajax
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return
}
if (this.status === 200) {
resolve(this.response)
} else {
reject(new Error(this.statusText))
}
}
const client = new XMLHttpRequest()
client.open("GET", url)
client.onreadystatechange = handler
client.responseType = "json"
client.setRequestHeader("Accept", "application/json")
client.send()
})
return promise
}
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json)
}, function(error) {
console.error('出错了', error)
})
如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例,此时的状态则由参数的Promise实例的状态决定。
Promise.prototype.then
then方法是定义在原型Promise.prototype上的,所以Promise实例对象也具有then方法,它的作用是为Promise实例添加状态改变时的回调函数,第一个参数是状态变为resolved时的回调函数,第二个参数是状态变为rejected时的回调函数(可省略)
then的返回值是一个新的Promise实例,所以可以采用链式写法,在then方法后面再调用另一个then方法,并且第一个then回调的结果会作为参数传给第二个then的回调函数
getJSON("/posts.json").then(function(json) {
return json.post
}).then(function(jsonPost) {
// ...
})
Promise.prototype.catch
catch方法同样位于原型中,用于指定发生错误时的回调函数
getJSON('/posts.json').then(function(posts) {
// ...
}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error)
})
Promise抛出错误(throw),会被catch方法捕获,reject方法的作用,等同于抛出错误,也会被catch捕获
const promise = new Promise(function(resolve, reject) {
reject(new Error('test'))
})
promise.catch(function(error) {
console.log(error)
})
// Error: test
如果 Promise 状态已经变成resolved,再抛出错误是无效的,因为Promise状态一旦改变,就不会再变
const promise = new Promise(function(resolve, reject) {
resolve('ok')
throw new Error('test')
})
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log(error) })
// ok
Promise对象的错误有冒泡性质,会一直向后传递,直到被捕获为止
getJSON('/post/1.json').then(function(post) {
return getJSON(post.commentURL)
}).then(function(comments) {
// some code
}).catch(function(error) {
// 处理前面三个Promise产生的错误
})
上面代码中,一共有三个 Promise 对象:一个由getJSON产生,两个由then产生。它们之中任何一个抛出的错误,都会被最后一个catch捕获
一般来说,不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),建议在Promise 对象后面跟着catch方法
catch方法返回的还是一个 Promise 对象,后面还可以接着调用then方法,如果没有报错,则会跳过catch方法,如果后面的then报错了则与前面的catch无关了
如果catch方法中有错误,后面可以再接着catch捕获前一个catch的错误
Promise.prototype.finally
finally方法的作用是不管 Promise 对象最后状态如何,都会执行的操作,finally方法的回调函数不接受任何参数
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···})
Promise.all
Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例,其接受一个数组作为参数,数组中每个元素都是 Promise 实例,如果不是就会调用Promise.resolve方法转为 Promise 实例
const p = Promise.all([p1, p2, p3]);
p的状态由p1、p2、p3决定,存在两种情况:
(1)只有p1、p2、p3的状态都变成resolved,p的状态才会变成resolved,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
Promise.race
Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例,参数与Promise.all方法一样。
const p = Promise.race([p1, p2, p3])
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数
const p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
])
p
.then(console.log)
.catch(console.error)
上面代码中,如果 5 秒之内fetch方法无法返回结果,变量p的状态就会变为rejected,从而触发catch方法指定的回调函数。
Promise.resolve
Promise.resolve()方法可以将现有对象转为 Promise 对象
Promise.reject
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected
网友评论