存在问题
1. 嵌套问题
在没有Promise
之前,我们通常都是通过回调函数来表示程序的异步,回调函数是我们程序的延续,回调函数是javascript中实现异步的最简单的方式,等待同步代码执行完的时候,在某个时间段内再执行回调函数。如果回调需要上一个回调的结果,那就会形成嵌套, 比如:
request(url1,{},function(val1){
request(url2, {data: val1}, function(val2){
request(url3, {data: val2}, function(val3){
}
}
})
复制代码
嵌套多了就形成了我们常常说的回调地域。回调地域有以下问题点:
- 难以追踪执行顺序,维护起来极其困难
- 代码脆弱性,可能动一处,处处动
- 程序异常执行异常,结果难以预测
2. 信任问题
信任问题产生的主要原因是把回调函数的控制权教给了第三方,这叫控制反转,我们无法预知第三方库到底什么时候会执行回调函数,所以我们会在回调函数里面做各种判断,比如像过早回调,过晚回调等等,而在每个这样的回调函数里面我们每次都要做这样重复的工作。大体情况如下:
- 调用回调过早
- 调用回调过晚
- 多次调用回调
- 不知是否回调
所以Promise
就是来解决上述问题的
如何解决上述存在的问题
1. 嵌套问题
Promise
在原型上定义了一个then 方法,并且会返回一个新的Promise
, 这样就形成了链式调用,这样也决定了调用顺序的问题,比如下面:
function ajax(url, data){
return new Promise((resolve, reject)=>{
request(url, data, function(res){
resolve(res)
})
})
}
ajax()
.then((res1)=> ajax(url1, res1))
.then((res2)=> ajax(url2, res2))
.then((res3)=> ajax(url3, res3))
复制代码
代码可读性提升了,顺序也可以很好的追踪到
2. 信任问题
- 过早调用。
Promise
的then方法的回调函数总是异步的,存在于微任务队列,所以不存在过早
- 过晚调用
Promise
在状态被敲定后,then方法注册的回调函数一定在下一次异步执行前调用,所以不存在过晚
- 多次调用
Promise
在状态被敲定后,是不能被改变的,所以只能执行一次回调
- 不知是否调用
只要注册了then的回调函数就一定会被调用
Promise 规范
Promise
使用了 Promise/A+ 规范,标准参考 英文版 中文版
Promise原型方法
1. then
then方法返回一个新的Promise
, 最多接受两个参数,一个是成功回调,另一个是失败回调
// p.then(onFulfilled[, onRejected]);
const promise1 = new Promise((resolve, reject) => {
// resolve('success');
reject('error!');
});
promise1.then((value) => {
console.log(value);
},(reason)=>{
console.log(reason)
});
复制代码
then的回调可以return返回值,规则如下:
- 如果返回的是一个值,那么then返回的Promise就成为接受状态,并将这个值作为接受状态的回调函数的参数
const promise1 = new Promise((resolve, reject) => {
resolve('success');
});
promise1.then((value) => {
console.log(value);
return 1
}).then((res)=>{
console.log(res) // 1
})
复制代码
- 如果没有返回值,那么then 返回的Promise就成为接受状态,并且接受状态的回调函数的参数是undefined
const promise1 = new Promise((resolve, reject) => {
resolve('success');
});
promise1.then((value) => {
console.log(value);
}).then((res)=>{
console.log(res) // undefined
})
复制代码
- 如果抛出一个错误,那么then返回的Promise就成为拒绝状态,并且将该错误信息作为拒绝状态的回调函数的参数
const promise1 = new Promise((resolve, reject) => {
resolve('success');
});
promise1.then((value) => {
console.log(value);
throw 'error'
}).then(null, (error)=>{
console.log(error)
})
复制代码
- 如果是一个接受状态的Promise, then 返回的Promise就是接受状态,并且将那个Promise的接受状态的回调函数的参数值作为该Promise接受状态回调函数的参数值
const promise1 = new Promise((resolve, reject) => {
resolve('success');
});
promise1.then((value) => {
console.log(value);
return Promise.resolve(22)
}).then((res)=>{
console.log(res) // 22
})
复制代码
- 如果是一个拒绝状态的Promise, then 返回的Promise就是拒绝状态,并且将那个Promise的拒绝状态的回调函数的参数值作为该Promise拒绝状态回调函数的参数值
const promise1 = new Promise((resolve, reject) => {
resolve('success');
});
promise1.then((value) => {
console.log(value);
return Promise.reject('error')
}).then(null, (error)=>{
console.log(error) // error
})
复制代码
- 如果是一个待定状态的Promise, then 返回的Promise就是待定状态,该Promise的终态和那个Promise的终态相同,而且该Promise的终态下的回调函数的参数就是那个Promise终态下的回调函数的参数值
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(123)
},2000)
})
Promise.resolve().then(() => {
return p1
}).then((res) => {
console.log(res) // 2s 后输出 123
})
复制代码
2. catch
catch也会返回一个Promise, 并且处理拒绝的情况, .catch() 其实只是没有给 onFulfilled 预留参数位置的 .then() 而已。可以改成成这样
Promise.prototype.catch = function(onRejected){
return this.then(null, onRejected)
}
复制代码
使用catch 捕捉错误
var p1 = new Promise(function(resolve, reject) {
resolve('Success');
});
p1.then(function(value) {
console.log(value); // "Success!"
throw 'oh, no!';
}).catch(function(e) {
console.log(e); // "oh, no!"
throw 'o'
})
复制代码
3. finally
finally() 方法返回一个Promise。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise是否成功完成后都需要执行的代码提供了一种方式。
这避免了同样的语句需要在then()和catch()中各写一次的情况。
// 比如加载动画
var loading = true
var p1 = new Promise(function(resolve, reject) {
resolve('Success');
});
p1.then(function(value) {
}).catch(function(e) {
}).finally(function(){
loading = false
})
复制代码
Promise 静态方法
1. all
all方法接受一个iterable类型(注:Array,Map,Set都属于ES6的iterable类型)参数,只返回一个promise实例,执行resolve的条件是,iterable中的promise的resolve都结束,并将所有resolve回调返回的结果组成数组,作为then的接受状态的回调函数的参数值;执行reject的条件是,iterable中只要有一个reject,并将这个reject的错误信息作为then的拒绝状态回调的参数值。
resolve的情况
//
var p1 = new Promise((resolve, reject) => {
resolve(1)
})
var p2 = new Promise((resolve, reject) => {
resolve(2)
})
var p3 = new Promise((resolve, reject) => {
resolve(3)
})
Promise.all([p1, p2, p3]).then((res) => {
console.log(res) // [1, 2, 3]
})
复制代码
reject的情况
var p1 = new Promise((resolve, reject) => {
resolve(1)
})
var p2 = new Promise((resolve, reject) => {
reject('error 2')
})
var p3 = new Promise((resolve, reject) => {
resolve(3)
})
Promise.all([p1, p2, p3]).then((res) => {
console.log(res)
}, (error) => {
console.log(error) // error 2
})
复制代码
2. allSettled
allSettled()方法返回一个所有给定promise都已经resolve 或者 reject 的promise, 并且返回一个对象数组,对象就是promise的结果
var p1 = new Promise((resolve, reject) => {
resolve(1)
})
var p2 = new Promise((resolve, reject) => {
reject('error 2')
})
Promise.allSettled([p1, p2]).then((res) => {
res.forEach(item => {
console.log(item)
})
})
//{status: "fulfilled", value: 1}
//{status: "rejected", reason: "error 2"}
复制代码
3. any
这个方法用于返回第一个成功的 promise 。只要有一个 promise 成功此方法就会终止,它不会等待其他的 promise 全部完成。接受一个iterable类型参数,没有一个promise成功就执行onRejected回调。
resolve的情况
var p1 = new Promise((resolve, reject) => {
resolve(1)
})
var p2 = new Promise((resolve, reject) => {
resolve(1)
})
var p3 = new Promise((resolve, reject) => {
reject('error 3')
})
Promise.any([p1, p2, p3]).then((res) => {
console.log(res) // 1
})
复制代码
reject的情况
var p1 = new Promise((resolve, reject) => {
reject(1)
})
var p2 = new Promise((resolve, reject) => {
reject('error 2')
})
Promise.any([p1, p2]).then((res) => {
console.log(res)
},(error)=>{
console.log(error) // AggregateError: All promises were rejected
})
复制代码
4. race
race方法返回一个promise, 一旦迭代器中的某一个promise接受或者拒绝,返回的promise也就接受或者拒绝,就是谁先敲定状态就返回谁的状态。方法接受一个iterable类型参数。
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, "one");
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "two");
});
Promise.race([p1, p2]).then(function(value) {
console.log(value); // "two"
// 两个都完成,但 p2 更快
});
复制代码
5. resolve
resolve返回一个解析过的promise对象,就是一个接受状态的promise。
参数如下:
- 一个值,该值作为then返回的promise接受状态的回调参数
- 没传或者undefined, 将undefined作为then返回的promise接受状态的回调参数
- promise对象,直接返回这个promise对象
var p1 = Promise.resolve(123)
var p2 = Promise.resolve()
var p3 = Promise.resolve(p1)
p1.then((res) => {
console.log(res)
})
p2.then((res) => {
console.log(res)
})
p3.then((res) => {
console.log(res)
})
// 123
// undefined
// 123
复制代码
6. reject
reject返回一个拒绝状态的promise对象, Promise.reject(reason) 参数reason拒绝的原因
var p1 = Promise.reject(new Error('error'))
p1.then(null, (reason) => {
console.log(reason)
})
// Error: error
复制代码
promise的相关信息就先介绍到这,下篇我们来通过Promise/A+ 的规范来手写一个MyPromise,并且实现以上方法,敬请期待