JS实现Promise
Promise概念
Promise 是异步编程的一种解决方案:从语法上讲,promise是一个对象,从它可以获取异步操作的消息;从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。
promise有三种状态: pending(等待态)
,fulfiled(成功态)
,rejected(失败态)
;状态一旦改变,就不会再变。创造promise实例后,它会立即执行。
promise解决的问题
- 回调地狱,代码难以维护, 常常第一个的函数的输出是第二个函数的输入这种现象
- promise可以支持多个并发的请求,获取并发请求中的数据
- 这个promise可以解决异步的问题,本身不能说promise是异步的.
分析Promise
如果我们想要封装promise就需要考虑以下几个问题
- 如何让Promise变成一个微任务
- 如何管理Promise的状态
- then方法的返回值问题
- 静态方法: resolve 、reject、all、race
Promise中函数的执行顺序
使用示例:new Promise(fn).then(handler)
执行顺序是:new Promise() -> 执行fn里的代码 -> then()函数添加handler队列 -> 异步resovle() -> 在resolveHandler里接收resolve的结果
手写Promise
/**
* 注意:promise本身不是异步的,它只是能处理异步
*/
class SimplePromise {
constructor(fn) {
if (typeof fn !== 'function') {
throw new Error('callback is not a function')
}
this.fn = fn
// 初始化状态,pending fulfiled rejected,状态变更后不能再改变
this.status = 'pending'
// resovle,reject回调函数队列
this.resovleQueue = []
this.rejectQueue = []
// new Promise()后,里面的代码是立即执行的
fn(this._resovle.bind(this), this._reject.bind(this))
return this
}
_resovle(value) {
// 调用完resolve()之后会走到then的resolveHandler函数
// 这里怎么能访问到resolveHandler呢?所以得提前在调用then方法的时候存起来
// then链式调用,后面的then会用到前面then的返回值
// 这里注意变成异步任务,否则resovle执行完了才会执行then函数添加handler,这样就访问不到handler了
// 正确的顺序应该是 new Promise() -> then函数添加handler到队列 -> resolve() -> 执行handler()
// setTimeout是宏任务,所以不准确
setTimeout(() => {
if (this.status !== 'pending') {
return
}
// 修改状态
this.status = 'fulfiled'
let res = value
while (this.resovleQueue.length) {
let handler = this.resovleQueue.shift()
res = handler(res)
}
}, 0)
}
_reject() {
if (this.status !== 'pending') {
return
}
this.status = 'rejected'
setTimeout(() => {
let res = value
while (this.rejectQueue.length) {
let handler = this.rejectQueue.shift()
res = handler(res)
}
}, 0)
}
// then的本质是调用then()来接收结果
// 封装then方法,有resolveHandler,rejectHandler两个参数
// 注意理解,调用then()方法的时候里面的代码还不会执行,要等resovle()之后then里面的代码才会执行
then(resolveHandler, rejectHandler) {
if (resolveHandler) {
this.resovleQueue.push(resolveHandler)
}
if (rejectHandler) {
this.rejectQueue.push(rejectHandler)
}
return this
}
// catch本质是reject
catch(rejectHandler) {
return this.then(undefined, rejectHandler)
}
// Promise.all([p1,p2...]).then([res1,res2...])
// 入参是迭代器,可以是Array,Map,Set
// 能使用then,所以Promise.all()会返回一个promise对象
static all(iterators) {
let promises = Array.from(iterators) // 转为数组
// results是从p.then()接收的,注意顺序是对应的
let results = new Array(promises.length)
let count = 0
return new SimplePromise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(res => {
results[i] = res
// 什么时候resovle results呢?
// 等所有结果响应的时候,所以需要一个计数器
count++
if (count === promises.length) {
resolve(results)
}
// 注意return,否则链式调用then获取不到上一个then的结果
return res
}).catch(err => {
reject(err)
})
}
})
}
// Promise.race([p1,p2...]).then(firstRes)
static race(iterators) {
let promises = Array.from(iterators)
return new SimplePromise((resolve, reject) => {
for (let p of promises) {
p.then(res => {
// 只要有一个结果响应了就resolve
resolve(res)
}).catch(() => {
reject()
})
}
})
}
// Promise.resolve(val).then()
static resovle(val) {
return new SimplePromise(resovle => {
resovle(val)
})
}
// Promise.reject(val).then()
static reject(val) {
return new Promise((resovle, reject) => {
reject(val)
})
}
}
// let p = new SimplePromise((resolve, reject) => {
// console.log(1)
// setTimeout(() => {
// resolve()
// }, 1000)
// }).then(res => {
// console.log(2)
// return 3
// }).then(res => {
// console.log(3)
// })
let p0 = SimplePromise.resovle('p0')
let p1 = new SimplePromise((resolve) => {
setTimeout(() => {
resolve('p1')
}, 1000)
})
let p2 = new SimplePromise((resolve) => {
setTimeout(() => {
resolve('p2')
}, 2000)
})
let p3 = new SimplePromise((resolve) => {
setTimeout(() => {
resolve('p3')
}, 5000)
})
// SimplePromise.all([p1, p2, p3]).then(results => {
// console.log(results);
// })
SimplePromise.race([p3, p2, p1, p0]).then(res => {
console.log(res)
})