$.ajax({
success: (res) => {
$.ajax({
success: (res) => {
$.ajax({
success: (res) => {
//...
}
})
}
})
}
})
复制代码
这就是典型的回调地狱,不只代码臃肿,可读性差,并且耦合度太高,不易维护。代码没法复用,还容易隐藏bug。前端
Promise规范的出现就是为了解决这种问题。ajax
这里强调一下,Promise是一种解决方案,它是一种规范。数组
ES6原生提供了Promise对象,在平常开发中常常会接触到Promise相关操做,本文将介绍Promise的使用方法及相关原理,但愿能有所帮助。promise
Promise有三种状态:异步
Promise的特色是状态只能由Pending转换为Fulfilled或Rejected,而且一旦改变再也不更改。函数
new Promise((resolve,reject) => {
/*executor*/
})
复制代码
Promise是一个带有resolve
,reject
两个参数的构造函数(executor
)。这个构造函数在Promise建立的时候当即执行,resolve和reject两个函数在被调用时,分别将Promise的状态更改成fulfilled(成功态)和rejected(失败态),并传递成功的值或失败的缘由。executor
内部一般会执行一些异步操做,当异步操做执行完毕时,可根据执行结果相应地调用resolve或reject(可能成功可能失败)。若是executor抛出一个错误,那么该Promise也将转为失败态。测试
Promise原型上还具备then和catch方法,调用后返回一个Promise实例,所以能够被链式调用。网站
每个Promise实例都带有一个then方法,该方法有两个参数(onFulfilled
,onRejected
),分别为Promise成功和失败时的回调。ui
let p = new Promise((resolve,reject) => {
resolve('success');
})
p.then(value => {
console.log(value); //success
}).then(value => {
console.log(value); //没有返回值时,undefined
})
复制代码
当返回了一个值或者一个成功态的Promise时,then返回的Promise都是成功态,若没有返回值时也是成功态,而回调函数的参数值为undefind
。spa
当抛出一个错误或者返回一个失败态Promise,then返回的Promise都是失败态。
let p = new Promise((resolve,reject) => {
reject('fail');
})
p.then(() => {
},err => {
console.log(err); //fail
});
复制代码
then方法传递的成功/失败函数,这两个函数能够返回一个promise;若是返回的是一个promise,则该promise状态将做为下一次then的结果。
let p = new Promise((resolve,reject) => {
resolve('success')
});
let p2 = new Promise((resolve,reject) => {
resolve('success2')
})
p.then(value => {
return p2; //p2的成功态将做为下一次then的状态
}).then(value => {
console.log(value)
})
复制代码
Promise.prototype.catch
方法返回也是一个Promise,使用方式同then方法,用于处理异常捕获状况。该方法捕获属于就近捕获原则,离错误最近的一个catch将会捕获错误并进行处理,后续将再也不捕获。
若失败状态被then方法中失败函数回调触发,则catch方法将不进行捕获。
let p1 = new Promise((resolve,reject) => {
resolve('success');
});
p1.then(value => {
throw 'a new error';
}).catch(e => {
console.log(e); //a new error
}).then(() => {
console.log('after a catch the chain is restored');
})
复制代码
Promise.all
方法返回一个新的Promise对象,在参数对象中全部的promise对象都成功时才会触发成功态,一旦有任意一个对象失败则当即触发该Promise对象的失败态。当触发成功态后,会把一个包含全部Promise返回值的数组按顺序返回。若是触犯失败态,则会把第一个失败的Promise对象错误信息返回。
let p1 = new Promise((resolve,reject) => {
setTimeout(() => {
resolve('p1')
},0)
});
let p2 = new Promise((resolve,reject) => {
setTimeout(() => {
resolve('p2')
},0)
});
let promise = Promise.all([p1,p2]).then(value => {
console.log(value); //['p1','p2']
})
复制代码
Promise.race方法是把参数中任意第一个完成状态转换的Promise做为成功或失败状态,并返回该Promise对象。
let p1 = new Promise((resolve,reject) => {
setTimeout(() => {
resolve('p1')
},1000)
});
let p2 = new Promise((resolve,reject) => {
setTimeout(() => {
reject('p2')
},0)
});
Promise.race([p1,p2]).then((value) => {
console.log(value)
},(err) => {
console.log(err); //p2
})
复制代码
Promise.resolve(value)返回一个成功态,而且将value传递给对应的then方法;
Promise.reject(reason)返回一个失败态,而且将reason传递个对应的then方法。
优势 | 缺点 |
---|---|
解决回调 | 没法监测进行状态 |
链式调用 | 新创建即执行且没法取消 |
减小嵌套 | 内部错误没法抛出 |
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
})
const promise2 = promise1.then(() => {
return 'an error'
})
console.log('promise1', promise1)
console.log('promise2', promise2)
setTimeout(() => {
console.log('promise1', promise1)
console.log('promise2', promise2)
}, 2000)
复制代码
const promise = new Promise((resolve, reject) => {
resolve('success1')
reject('error')
resolve('success2')
})
promise.then((res) => {
console.log('then: ', res)
})
.catch((err) => {
console.log('catch: ', err)
})
复制代码
Promise.resolve(1)
.then((res) => {
console.log(res)
return 2
})
.catch((err) => {
return 3
})
.then((res) => {
console.log(res)
})
复制代码
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('executor')
resolve('success')
}, 1000)
})
const start = Date.now()
promise.then((res) => {
console.log(res, Date.now() - start)
})
promise.then((res) => {
console.log(res, Date.now() - start)
})
//Promise的构造函数只执行一次,而且当即执行;promise的then方法能够被屡次调用,每次都返回新的promise实例。
复制代码
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('executor')
resolve('success')
}, 1000)
})
const promise2 = promise.then(res => {
console.log(res);
})
promise2.then(res => {
console.log(res)
})
复制代码
Promise.resolve()
.then(() => {
return new Error('error!!!')
})
.then((res) => {
console.log('then: ', res)
})
.catch((err) => {
console.log('catch: ', err)
})
复制代码
Promise.resolve()
.then(() => {
throw new Error('error'); //return Promise.reject('error')
})
.then((res) => {
console.log('then: ', res)
})
.catch((err) => {
console.log('catch: ', err)
})
复制代码
then或catch方法返回一个错误对象并不会被捕获,只有在抛出错误或返回失败态时才会引发捕获。
const promise = Promise.resolve()
.then(() => {
return promise
})
promise.catch(e => {
console.log(e)
})
//[TypeError: Chaining cycle detected for promise #<Promise>]
复制代码
返回值不能是promise实例自己,由于此时实例并未构建完成,形成死循环,所以抛出类型错误。
process.nextTick(() => {
console.log('nextTick')
})
Promise.resolve()
.then(() => {
console.log('then')
})
setImmediate(() => {
console.log('setImmediate')
})
console.log('end')
复制代码
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
复制代码
then和catch方法的参数是一个函数,若非函数则发生穿透
该网站介绍了若须要实现Promise须要实现的规范方法。当多个库实现本身的Promise类时,为了能实现相应的效果,该规范提供了实现标准,并提供了promises-aplus-tests
测试包测试实现能力。
后续将推出文章介绍如何实现本身的Promise类,敬请期待!