一、Promise源码一步一步手撕
本文章将通过promise的基本使用和一些promise的特性,来一步一步完成我们自己的promise。
+
代表新增代码
1. 创建promise,可以修改状态、保存值,状态只能修改一次
接收一个执行器回调函数在内部立即调用,该回调函数接收两个参数resolve
,reject
,可以改变promise对象的状态且保存值,所以我们需要实现这两个函数,且promise内部维护一个值result
和一个状态state("pengding","fulfilled","rejected")
,这个状态只能修改一次,在调用resolve()
和reject()
都是无效的。
js
const promise = new Promise((resolve, reject) => {
resolve() //该promise为fulfilled
reject() // 无效,该promise还是为fulfilled
})
const promise = new Promise((resolve, reject) => {
reject() //该promise为rejected
})
const promise = new Promise((resolve, reject) => {
throw new Error('抛出错误') //该promise为rejected
})
js
class Promise{
constructor(executor) {
// 保存每个promise实例对象的状态 默认为pending
this.state = 'pending'
// 存储promise对象的数据
this.result = null
// 在其他地方调用resolve和reject函数,会导致this绑定到window
const that = this
// 改变promise实例对象状态为fulfilled
function resolve(data) {
// 保证只能修改一次状态 其他状态下无法再次修改
if(that.state === 'pending') {
that.state = 'fulfilled'
that.result = data
}
}
// 改变promise实例对象状态为rejected
function reject(data) {
// 保证只能修改一次
if(that.state === 'pending'){
that.state = 'rejected'
that.result = data
}
}
// 执行构造器回掉函数
try {
// 传入resolve和reject函数
executor(resolve, reject)
}catch (e){
// 如果抛出异常则直接变为rejected状态
reject(e)
}
}
}
2. 一个promise 指定的多个成功/失败回调函数都会调用
在一个promise对象上注册的多个成功/失败回调函数,在状态改变的时候,都会执行。
js
const promise = new Promise((resolve, reject) => {})
promise.then(res=>{},reason=>{})
promise.then(res=>{},reason=>{})
then方法
接收一个成功和一个失败回调函数,在状态改变时所有的回调函数都会执行,此时我们需要一个callbacks
数组来保存全部的回调函数。
js
class Promise{
constructor(executor) {
// 保存每个promise实例对象的状态 默认为pending
this.state = 'pending'
// 存储promise对象的数据
this.result = null
+ // 保存每个promise实例对象的回掉函数 以对象{成功/失败}存储
+ this.callbacks = []
// 在其他地方调用resolve和reject函数,会导致this绑定到window
const that = this
// 改变promise实例对象状态为fulfilled
function resolve(data) {
// 保证只能修改一次状态 其他状态下无法再次修改
if(that.state === 'pending') {
that.state = 'fulfilled'
that.result = data
+ // 遍历执行所有成功回掉函数
+ that.callbacks.forEach(item => item.onResolved())
}
}
// 改变promise实例对象状态为rejected
function reject(data) {
// 保证只能修改一次
if(that.state === 'pending'){
that.state = 'rejected'
that.result = data
+ // 遍历执行所有失败回掉函数
+ that.callbacks.forEach(item => item.onRejected())
}
}
// 执行构造器回掉函数
executor(resolve, reject)
}
// then方法
+ then(onResolved, onRejected){
+
+ }
}
3. 改变 promise 状态和指定回调函数先后顺序
同步改变: 在一个已有状态的promise对象上注册了回调函数,则对应状态的回调函数会立即进入微任务队列等待执行
异步改变: 在一个"pending"
状态的promise对象上注册回调函数,该回调函数会保存起来,等待状态改变再进入微任务队列等待执行
现在来继续完善我们的then方法,暂时不需要
constructor
构造函数,所以直接写then
方法
js
class Promise{
constructor(executor){}
// then函数实现
then(onResolved, onRejected){
// 执行回掉函数 通过setTimeout模拟进入微任务队列
const callback = (type) => {
setTimeout(()=>{
// 调用回调需要传result进去
type(this.result)
})
}
// 当前成功状态下直接调用then成功回掉 回掉函数直接进入微任务队列
if(this.state === 'fulfilled') {
callback(onResolved)
// 当前失败状态下直接调用then失败回掉 回掉函数直接进入微任务队列
}else if(this.state === 'rejected') {
callback(onRejected)
// 当前pending状态调用then 注册成功和失败回掉函数 等待状态改变对应回掉函数进入微任务队列
}else{
// 把成功/失败回掉函数加入callbacks数组
this.callbacks.push({
// 执行onResolved() 就会执行callback(onresolved)
onResolved: () => {
callback(onResolved)
},
// 执行onResolved() 就会执行callback(onresolved)
onRejected: () => {
callback(onRejected)
}
})
}
}
}
4. then()
返回的promise的状态由回调函数执行结果决定,未执行回调函数时为"pending"
状态
抛出异常: then()
返回的promise状态变为"rejected"
,值为抛出的异常
返回非promise的任意值: then()
返回的promise状态变为"fulfilled"
值为回调函数返回的值
返回promise: then()
返回的promise状态为回调函数返回的promise的状态,值为回调函数返回的promise的值
js
// promise的状态为rejected
const promise = Promise.resolve().then(res=>{
throw new Error('then回调中抛出错误')
})
// promise的状态为fulfilled
const promise = Promise.resolve().then(res=>{
return 1
})
// promise的状态为返回promise状态:state=rejected,result='我是失败的promise'
const promise = Promise.resolve().then(res=>{
return Promise.reject('我是失败的promise')
})
简单的使用之后,我们来完善我们then()
方法中的逻辑,因为执行回调都是在callback函数中,所以我们只要关注callback函数如何写就可以,但是在这个前提下我们需要给then()
方法返回一个promise对象
js
class Promise{
constructor(executor){}
// then函数实现
then(onResolved, onRejected){
+ return new Promise((resolve, reject)=>{
// 执行回掉函数 通过setTimeout模拟进入微任务队列
const callback = (type) => {
setTimeout(()=>{
+ try{
+ let res = type(this.result)
+ // 如果执行结果返回的是promise
+ if(res instanceof Promise) {
+ // 执行结果返回的promise状态决定then返回的promise状态
+ res.then(v => {
+ // 执行结果返回promise状态为fulfilled
+ resolve(v)
+ }, r => {
+ // 执行结果返回promise状态为rejected
+ reject(r)
+ })
+ // 如果执行结果返回的不是promise
+ }else {
+ resolve(res)
+ }
+ }catch (e){
+ // 如果抛出错误则then返回的promise状态为rejected
+ reject(e)
+ }
})
}
// 当前成功状态下直接调用then成功回掉 回掉函数直接进入微任务队列
if(this.state === 'fulfilled') {
callback(onResolved)
// 当前失败状态下直接调用then失败回掉 回掉函数直接进入微任务队列
}else if(this.state === 'rejected') {
callback(onRejected)
// 当前pending状态调用then 注册成功和失败回掉函数 等待状态改变对应回掉函数进入微任务队列
}else{
// 把成功/失败回掉函数加入callbacks数组
this.callbacks.push({
// 执行onResolved() 就会执行callback(onresolved)
onResolved: () => {
callback(onResolved)
},
// 执行onResolved() 就会执行callback(onresolved)
onRejected: () => {
callback(onRejected)
}
})
}
+ })
}
}
5. then()
链式调用传递性:异常传透和值传递
失败传递: 未指定失败回调可以将失败值传递给后面的回调函数处理,在最后通过catch方法捕获
值传递: 未指定成功回调可以将成功值传递给后面的回调函数处理。
js
Promise.resolve(data)
.then()
.then(1)
// data被传递到第三个then中
.then(data=>{throw new Error('中途出错啦')})
.then(data=>{})
// error直接被传递到最后的catch中
.catch(err=>{console.log(err)})
这里补充一下,其实catch()
方法很简单,就是调用的then()
方法,只是第一个参数传入了undefined
js
class Promise{
// 构造函数
constructor(exector){}
// then方法
then(onResolved, onRejected){}
// catch方法
+ catch(onRejected){
+ this.then(undefined, onRejected)
+ }
}
继续完善我们的then()
方法,then的第一个参数如果不是一个函数,则需要赋值一个函数可以将promise的成功状态传递下去,如果第二个参数不是一个函数,则需要赋值一个函数可以将promise的失败状态传递下去
js
class Promise{
constructor(executor){}
// then函数实现
then(onResolved, onRejected){
+ // (传递性)如果回掉函数为空,则需要传递成功值或者失败值
+ if(typeof onRejected !== 'function') {
+ onRejected = reason => throw reason
+ }
+ if(typeof onResolved !== 'function') {
+ onResolved = value => value
+ }
return new Promise((resolve, reject)=>{
// 执行回掉函数 通过setTimeout模拟进入微任务队列
const callback = (type) => {
setTimeout(()=>{
try{
let res = type(this.result)
// 如果执行结果返回的是promise
if(res instanceof Promise) {
// 执行结果返回的promise状态决定then返回的promise状态
res.then(v => {
// 执行结果返回promise状态为fulfilled
resolve(v)
}, r => {
// 执行结果返回promise状态为rejected
reject(r)
})
// 如果执行结果返回的不是promise
}else {
resolve(res)
}
}catch (e){
// 如果抛出错误则then返回的promise状态为rejected
reject(e)
}
})
}
// 当前成功状态下直接调用then成功回掉 回掉函数直接进入微任务队列
if(this.state === 'fulfilled') {
callback(onResolved)
// 当前失败状态下直接调用then失败回掉 回掉函数直接进入微任务队列
}else if(this.state === 'rejected') {
callback(onRejected)
// 当前pending状态调用then 注册成功和失败回掉函数 等待状态改变对应回掉函数进入微任务队列
}else{
// 把成功/失败回掉函数加入callbacks数组
this.callbacks.push({
// 执行onResolved() 就会执行callback(onresolved)
onResolved: () => {
callback(onResolved)
},
// 执行onResolved() 就会执行callback(onresolved)
onRejected: () => {
callback(onRejected)
}
})
}
})
}
// catch方法
catch(onRejected){}
}
6. Promise.resolve()
静态类方法
通过该函数,可以对传入的data快速生成一个promise对象,如果传入的data为promise,则生成的promise对象状态和值都为data的状态和值,否则生成的promise的状态为"fulfilled"
且值为data
js
const promise = Promise.resolve(1) //state='fulfilled' result=1
const promise = Promise.resolve(new Error) // state='fulfilled' result=Error()
const promise = Promise.resolve(new Promise((resolve, reject) =>reject(1)))//state='rejected' result=1
js
class Promise{
// 构造函数
constructor(executor){}
// then方法
then(onResolved, onRejected){}
// catch方法
catch(onRjected)
// resolve类方法
static resolve(data){
return new Promise((resolve, reject) => {
// 如果为promise对象
if(data instaceof Promise){
data.then(res=>resolve(res),err=>reject(err))
// 不是promise对象
}else{
resolve(data)
}
})
}
}
7. Promise.reject()
静态类方法
通过该函数,可以对传入的data快速生成一个promise对象,状态为"rejected"
,值为data
js
const promise = Promise.reject(1) //state='rejected' result=1
const promise = Promise.reject(new Error) // state='rejected' result=Error()
const promise = Promise.reject(new Promise((resolve, reject) =>resolve(1)))//state='rejected' result=Promise<state="fulfilled" result=1>
js
class Promise{
// 构造函数
constructor(executor){}
// then方法
then(onResolved, onRejected){}
// catch方法
catch(onRjected)
// resolve类方法
static resolve(data){}
// reject类方法
static reject(data) {
return new Promise((resolve, reject) => reject(data))
}
}
8. Promise.all()
静态类方法
传入一个promise数组,返回一个promise,该promise的状态由传入promise数组的状态来决定,如果该数组内全部promise的状态为"fulfilled"
则该promise的状态为"fulfilled"
且值为数组内全部promise的值的数组
js
const promise = Promise.all([Promise.resolve(1), Promise.resolve(2)]) //state="fulfilled" result=[1,2]
const promise = Promise.all([Promise.resolve(1), Promise.reject(2)]) //state="rejected" result=2
js
class Promise{
// 构造函数
constructor(executor){}
// then方法
then(onResolved, onRejected){}
// catch方法
catch(onRjected)
// resolve类方法
static resolve(data){}
// reject类方法
static reject(data) {}
// all类方法
static all(promises) {
return new Promise((resolve, reject) => {
let count = 0
let result = []
for(let i = 0; i < promises.length; i++) {
// 遍历全部promise,注册回调函数
promises[i].then(value => {
// 有成功就把值加入数组
result[i] = value
// 记录成功的数量
count++
// 如果全部都成功了
if(count === promises.length) {
// 改变promise状态为成功且值为数组result
resolve(result)
}
}, reason => {
// 失败情况
reject(reason)
})
}
})
}
}
8. Promise.race()
静态类方法
传入promise数组 返回一个promise,该promise的状态和值为传入的promise数组中第一个有状态的promise对应的状态和值
js
const promise1 = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve(1)
},1000)
})
const promise1 = new Promise((resolve, reject)=>{
setTimeout(()=>{
reject(2)
},2000)
})
const promise = Promise.race([promise1, promise2])//state='fulfilled' result=1
js
class Promise{
// 构造函数
constructor(executor){}
// then方法
then(onResolved, onRejected){}
// catch方法
catch(onRjected)
// resolve类方法
static resolve(data){}
// reject类方法
static reject(data) {}
// all类方法
static all(promises) {}
// race类方法
static race(promises) {
return new Promise((resolve, reject) => {
for(let i = 0; i < promises.length; i++){
// 全部promise注册回调函数
promises[i].then(value => {
// 谁第一个执行回调就是谁的状态和值
resolve(value)
}, reason => {
reject(reason)
})
}
})
}
}
二、总结
大家如果跟着一步一步实现到这里,相信对promise的底层实现,包括在面试中肯定都没有问题了。完整代码就不贴出来啦,如果上面步骤跟着写肯定已经有完整的版本了。