在实际的JavaScript开发中,我们需要使用到很多的异步开发。如我们需要在页面中使用JavaScript实现一系列动画效果,那么每个动画效果都要靠异步完成。当每个动画效果完成后,就会通过一个回调函数通知逻辑代码。为了实现动画效果的顺序展示,我们需要把这些动画效果的方法“串”起来:
animate1(() => {
animate2(() => {
animate3(() => {
animate4(() => {
// ...
})
})
})
})
后来有人提出了Promise概念,这个概念意在让异步代码变得干净和直观:
animate1()
.then(() => animate2())
.then(() => animate3())
.then(() => animate4())
.then(() => {
// ...
})
Promise最大的目的在于可以让异步代码变得井然有序,就如我们需要在浏览器访问一个以JSON作为返回格式的第三方API,在数据下载完成后进行JSON解码,通过Promise来包装异步流程可以使代码变得非常干净整洁:
fetch('http://example.com/api/users/top')
.then(res => res.json())
.then(data => {
//...
})
// 处理错误
.catch(err => console.error(err))
Promise在设计上具有原子性,即只有三种状态:等待(Pending)、成功(Fulfilled)、失败(Rejected)。
基本语法
要想给一个函数赋予Promise的能力,就要先创建一个Promise对象,并将其作为函数值返回。Promise构造函数要求传入一个带有resolve和reject参数的函数。resolve和reject是两个用于结束Promise等待的函数,对应的状态分别为成功和失败:
function asyncMethod(...args) {
return new Promise((resolve, reject) => {
// ...
})
}
将新创建的Promise对象作为异步方法的返回值,所有的状态就可以使用它所提供的放阿飞进行控制了。
进行异步操作
通过resolve(value)和reject(reason)方法来控制Promise的原子状态:
new Promise((resolve, reject) => {
api.call('fetch-data', (err, data) => {
if(err) return reject(err) // 进入成功状态
resolve(data) // 进入失败状态
})
})
在Pomise的首层函数作用域中,一旦出现throw语句,会直接进入失败状态:
(new Promise(function() {
throw new Error('test')
}))
.catch(err => console.error(err))
但是相对应的return语句并不会使Promise对象进入成功状态。
处理Promise的状态
Promise对象,有两个与resolve(value)和reject(reason)方法对应的用于处理状态变化的方法
方法 | 方法内容 |
---|---|
promise.then(onFulfilled[,onRejected]) | 处理成功状态并接收返回值,也可以处理失败状态并处理失败的原因(可选) |
promise.catch(onReject) | 处理Promise对象的失败状态并处理失败的原因 |
- 如果onFulfilled或onRejected中所返回的值是一个Promise对象;
- 如果onFulfilled或onRejected中返回值并不是一个Promise对象,则会返回一个已进入成功状态的Promise对象;
- 如果onFulfilled或onRejected中因throw语句而抛出一个错误err,则会返回一个已进入
失败状态的Promise对象;
以上返回的Promise对象都会被加入到Promise的处理链中,呈现出流水线作业模式:
asyncMethod()
.then((...args) => args /* ... */ )
.catch(err => console.error(err))
因此我们可以利用Promise对象链的流水线作业模式来实现动画效果:
animate1()
.then(() => animate2())
.then(() => animate3())
.then(() => animate4())
.then(() => {
// ...
})
Promise对象链的传递性
以往回调的方式,一旦某个环节出了错误,就需要在每个回调函数中进行错误处理,但在Promise对象链中可以实现集中处理甚至分块处理。Promise对象链中某一环节出现错误,便会从出错的环节开始,不断向下传递,直到出现任何一环的Promise对象对错误进行响应为止:
animate1()
.then(() => animate2()) // 向下传递
.then(() => animate3()) // 向下传递
.then(() => animate4()) // 向下传递
.catch(err => {
console.error(err)
return animate5()
})
.then(/* ... */) // 向下传递
.catch(err => console.error(err))
Promise工具方法
- Promise.all(iterable)
该方法传入一个可迭代对象(如数组),返回一个Promise对象,该Promise对象会在当前可迭代对象的所有Promise对象都进入完成状态(包括成功和失败)后被激活:
const promise = [ async(1), async(2), async(3), async(4) ]
Promise.all(promise)
.then(values => {
// ...
})
.catch(err => console.error(err))
- Promise.race(iterable)
与Promise.all(iterable)类似,不过该Promise对象会在当前可迭代对象的某一Promise对象进入完成状态(包括成功和失败)后就被激活:
const promise = [ async(1), async(2), async(3), async(4) ]
Promise.race(promise)
.then(values => {
// ...
})
.catch(err => console.error(err))
网友评论