一种更优的异步编程统一方案,可是直接使用传统回调方式去完成复杂的异步流程会形成大量的回调问题(回调地狱),CommonJS社区提出了Promise的规范,目的就是为异步编程提供更合理更规范的统一解决方案,在ES2015中被标准化,成为语言规范。javascript
Promise就是一个对象,用来表示一个异步任务最终结束以后到底是成功仍是失败,就像是内部对外界作出了一个承诺,一开始这个承诺是待定的状态(pending),最终有多是成功(Fulfilled)对应的回调函数为onFulfilled,也多是失败(Rejected)对应的回调函数为onRejected。java
示例:node
// Promise接收一个函数,函数有两个参数(都是函数),resolve和reject
const promise = new Promise(function (resolve, reject) {
// resolve函数的做用就是把Promise的状态修改成Fulfilled
// 成功的结果就是经过这个resolve传递出去
resolve(100)
// reject函数的做用就是把Promise的状态修改成Rejected
// 失败的结果经过这个reject传递出去
// reject传递的参数通常是一个错误对象,描述错误的缘由
reject(new Error('promise rejected'))
})
promise.then(function(value) {
// 当返回resolve时会调用这个回调函数
console.log('resolve', value) // => 100
}, function(err) {
// 当返回reject时会调用这个回调函数
console.log('rejected', err) // => Error对象
})
复制代码
onRejected是为Promise中的异常作一些处理,如:Promise主动调用reject方法、调用一个不存的方法、主动抛出一个Error异常。ajax
经过Promise的catch方法捕获异常编程
promise.then(function(value) {
// 当返回resolve时会调用这个回调函数
console.log('resolve', value) // => 100
})
.catch(function(err) { // catch方法其实就是reject方法的一个别名
// 当返回reject时会调用这个回调函数
console.log('rejected', err) // => Error对象
})
复制代码
catch不then方法第二个参数捕获异常的不一样点:json
若是在Promise链条中发生异常,这个异常会被一直日后传递,直到被捕获,因此catch方法更像是给整个链条注册的异常捕获。api
resolve方法直接将值返回数组
示例:promise
Promise.resolve('foo')
.then(function(value) {
console.log(value) // => foo
})
// 上边获得的value就和下边这种同样
new Promise(function(resolve, reject) {
resolve('foo')
})
复制代码
使用Promise对象的静态方法resolve包装一个Promise,获得的是本来被包装的Promise 示例:异步
let promise = ajax('/api/users.json')
let promise2 = Promise.resolve(promise)
console.log(promise === promise2) // => true
复制代码
Promise的resolve方法返回一个带有then方法的对象,这个对象也具备onFulfilled方法时,咱们也能够经过then方法拿到返回的值 示例:
Promise.resolve({
then: function(onFulfilled, onRejected) {
onFulfilled('foo')
}
})
.then(function(value) {
console.log(value) // => foo
})
复制代码
与resolve静态方法对应的是reject静态方法,reject静态方法返回就是错误信息,使用上和resolve相似,如:Promise.reject(new Error('xxx'))
当有多个异步任务须要同时处理时,在以前是经过定义一个计数器的形式来判断全部异步任务是否都执行完成。在Promise中如今给咱们提供了一个能够同时处理多个异步任务的方法:all。
示例:
let promise = Promise.all([
ajax('/api/users.json'),
ajax('/api/posts.json')
])
// all方法会当全部异步任务都执行完成以后返回一个Promise对象
// 只有当全部异步任务都成功时才返回resolve,不然返回reject
peomise.then(function(value) {
// value传递的为一个数组,数组中包括全部异步任务的执行结果
console.log(value) // => [xx, xx]
})
复制代码
race方法也一样能够将多个Promise对象组合为一个全新的Promise对象,与all方法不一样的是all方法等待全部异步任务结束以后结束;race方法是只会等待第一个异步任务结束后结束,也就是只要其中任何一个异步任务完成以后race方法就会结束。
示例:
const request = ajax('/api/posts.json')
const timer = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('timeout')), 500)
})
Promise.race([
request,
timer
])
.then(value => {
// 若是500ms之内request方法成功则执行成功的回调
console.log(value)
})
.catch(err => {
// 若是500ms之内request方法没有成功,则执行失败的回调
console.log(err)
})
复制代码
回调队列中任务一般被称做宏任务,宏任务执行过程当中可能会添加一些额外的需求,新添加的需求能够选择做为一个新的宏任务进入到队列中排队,例如setTimeout会在宏任务中排队,也能够做为一个微任务,直接在当前任务结束以后当即执行。 Promise的回调做为微任务执行,在本轮调用结束的末尾当即执行。 微任务:为了提升总体的响应能力 目前绝大多数异步调用都是做为宏任务执行,而Promise对象、MutationObserver、node中的process.nextTick是做为微任务执行
示例:
console.log('begin')
// 做为宏任务执行
setTimeout(() => {
console.log('timer')
}, 0)
// 做为微任务执行
Promise.resolve()
.then(() => {
console.log('promise')
})
.then(() => {
console.log('promise2')
})
console.log('end')
// => begin => end => promise => promise2 => timer
复制代码