什么是Promise?
描述
一个 Promise
对象代表一个在这个 promise 被创建出来时不一定已知值的代理。它让你能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来。这样使得异步方法可以像同步方法那样返回值:异步方法并不会立即返回最终的值,而是会返回一个 promise,以便在未来某个时候把值交给使用者。
一个 Promise
必然处于以下几种状态之一:
- 待定(pending):初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled):意味着操作成功完成。
- 已拒绝(rejected):意味着操作失败。
待定状态的 Promise 对象要么会通过一个值被兑现,要么会通过一个原因(错误)被拒绝。当这些情况之一发生时,我们用 promise 的 then
方法排列起来的相关处理程序就会被调用。如果 promise 在一个相应的处理程序被绑定时就已经被兑现或被拒绝了,那么这个处理程序也同样会被调用,因此在完成异步操作和绑定处理方法之间不存在竞态条件。
应用场景举例:
对于数组的filter方法,里面实现的过滤的逻辑,实现了如何过滤,但是过滤的条件是什么,filter方法中提供回调函数,让我们自己写。为提高程序的通用性,调用者提供一个过滤条件函数,这样filter函数借此调用调用者的函数来进行过滤。
解决了什么
1.回调地狱问题 2.代码的可读性问题
什么是回调地狱
所谓回调地狱就是指把函数作为参数层层嵌套请求,这样层层嵌套,人们称之为回调地狱,代码阅读性非常差。举个列子
手写简易版Promise
class Promise2 {
#status = 'pending'
constructor(fn){
this.q = []
const resolve = (data)=>{
this.#status = 'fulfilled'
const f1f2 = this.q.shift()
if(!f1f2 || !f1f2[0]) return
const x = f1f2[0].call(undefined, data)
if(x instanceof Promise2) {
x.then((data)=>{
resolve(data)
}, (reason)=>{
reject(reason)
})
}else {
resolve(x)
}
}
const reject = (reason)=>{
this.#status = 'rejected'
const f1f2 = this.q.shift()
if(!f1f2 || !f1f2[1]) return
const x = f1f2[1].call(undefined, reason)
if(x instanceof Promise2){
x.then((data)=>{
resolve(data)
}, (reason)=>{
reject(reason)
})
}else{
resolve(x)
}
}
fn.call(undefined, resolve, reject)
}
then(f1, f2){
this.q.push([f1, f2])
}
}
const p = new Promise2(function(resolve, reject){
setTimeout(function(){
reject('出错')
},3000)
})
p.then( (data)=>{console.log(data)}, (r)=>{console.error(r)} )
手写 Promise.all
Promise.all() 方法接收一个 promise 的 iterable 类型(注:Array,Map,Set 都属于 ES6 的 iterable 类型)的输入,并且只返回一个Promise
实例, 那个输入的所有 promise 的 resolve 回调的结果是一个数组。这个Promise
的 resolve 回调执行是在所有输入的 promise 的 resolve 回调都结束,或者输入的 iterable 里没有 promise 了的时候。它的 reject 回调执行是,只要任何一个输入的 promise 的 reject 回调执行或者输入不合法的 promise 就会立即抛出错误,并且 reject 的是第一个抛出的错误信息。
要点:
- 知道要在 Promise 上写而不是在原型上写
- 知道 all 的参数(Promise 数组)和返回值(新 Promise 对象)
- 知道用数组来记录结果
- 知道只要有一个 reject 就整体 reject
//Promise.prototype.myAll
Promise.myAll = function(list){
const results = []
let count = 0
return new Promise((resolve,reject) =>{
list.map((item, index)=> {
item.then(result=>{
results[index] = result
count += 1
if (count >= list.length) { resolve(results)}
}, reason => reject(reason) )
})
})
}