最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 手写promise实现过程

    正文概述 掘金(sneve)   2021-01-01   321

    原生promise用法:

    new Promise((resolve, reject) => {
        resolve("done")
    })
    

    现在来自己开发一个Promise实现,提升异步编程的能力。

    1 声明promise类并绑定this

    class PM {
        // 使用静态属性保存状态值
        static PENDING = "pending";
        static FULFILLED = "fulfilled";
        static REJECTED = "rejected";
        // executor为执行者
        constructor(executor) {
            this.status = PM.PENDING;
            this.value = null;
            executor(this.resolve, this.reject)
        }
    
        resolve(value) {
            this.status = PM.FULFILLED;
            this.value = value
        }
    
        reject(reason) {
            this.status = PM.REJECTED;
            this.value = reason
        }
    }
    

    测试代码:

    <script>
      let p = new PM((resolve, reject) => {
        resolve("done");
      });
      console.log(p)
    </script>
    

    测试结果: 手写promise实现过程

    报错原因:因为 resolve或reject方法在executor中调用,作用域也是executor作用域,这会造成this指向window,现在我们使用的是class定义,this为undefined。

    修改constructor代码:

    constructor(executor) {
        this.status = PM.PENDING;
        this.value = null;
        // 增加错误捕获,当执行者出现错误时触发拒绝状态
        try {
            // 绑定this值,指向当前class
            executor(this.resolve.bind(this), this.reject.bind(this))
        } catch (error) {
            this.reject(error)
        }
    }
    constructor(executor) {
        this.status = PM.PENDING;
        this.value = null;
        // 绑定this值,指向当前class
        executor(this.resolve.bind(this), this.reject.bind(this)) 
    }
    

    再次测试,结果:

    手写promise实现过程

    2 实现状态保护

    测试代码:

    <script>
    let p = new PM((resolve, reject) => {
         resolve("done")
         reject("fail")
    });
    console.log(p)
    </script>
    

    测试结果:

    手写promise实现过程

    结果不符合原生promise定义,状态只能改变一次,在resolve与reject中添加判断即可:

    resolve(value) {
        // 添加状态判断
        if (this.status === PM.PENDING) {
            this.status = PM.FULFILLED;
            this.value = value
        }
    }
    
    reject(reason) {
        // 添加状态判断
        if (this.status === PM.PENDING) {
            this.status = PM.REJECTED;
            this.value = reason
        }
    }
    

    3 then的基础构建与异常捕获

    原生promise的then方法:

    new Promise((resolve, reject) => {
        resolve("done")
        // reject("fail")
    }).then(value => {
        console.log("resolve", value)
    }, reason => {
        console.log("reason", reason)
    })
    

    自定义class添加基础then方法:

    then(onFulfilled, onRejected) {
        if (this.status === PM.FULFILLED) {
            onFulfilled(this.value)
        }
        if (this.status === PM.REJECTED) {
            onRejected(this.value)
        }
    }
    

    测试代码:

    <script>
    let p = new PM((resolve, reject) => {
      resolve("done")
      // reject("fail")
    }).then(value => {
      console.log("resolve", value)
    }, reason => {
      console.log("reason", reason)
    })
    </script>
    

    测试结果:

    手写promise实现过程

    现在执行以下测试代码:

    <script>
    let p = new PM((resolve, reject) => {
       reject("fail")
    }).then(value => {
       console.log("resolve", value)
    })
    </script>
    

    结果报错:

    手写promise实现过程

    现在完善then方法来处理状态的改变:

    then(onFulfilled, onRejected) {
        // then的每个方法都不是必须的,所以当没有传递时给上默认值
        if (typeof onFulfilled !== "function") {
            onFulfilled = () => { }
        }
        if (typeof onRejected !== "function") {
            onRejected = () => { }
        }
        // 当执行then传递的函数发生异常时,统一交给onRejected来处理错误
        if (this.status === PM.FULFILLED) {
            try {
                onFulfilled(this.value)
            } catch (error) {
                onRejected(error)
            }
        }
        if (this.status === PM.REJECTED) {
            try {
                onRejected(this.value)
            } catch (error) {
                onRejected(error)
            }
        }
    }
    

    4 实现then的异步操作

    先执行原生promise:

    new Promise((resolve, reject) => {
        resolve("原生done")
    }).then(value => {
        console.log("resolve", value)
    })
    console.log("同步代码")
    

    原生结果:

    手写promise实现过程

    然后使用自定义方法,执行测试代码:

    <script>
    let p = new PM((resolve, reject) => {
        resolve("自定义done")
    }).then(value => {
        console.log("resolve", value)
    })
    console.log("同步代码")
    </script>
    

    测试结果:

    手写promise实现过程

    结果顺序不一致原因:目前的代码产生的Promise不是异步的。

    修改then里面的方法:

    if (this.status === PM.FULFILLED) {
        // 使用setTimeout来将onFulfilled与onRejected做为异步宏任务执行
        setTimeout(() => {
            try {
                onFulfilled(this.value)
            } catch (error) {
                onRejected(error)
            }
        })
    }
    if (this.status === PM.REJECTED) {
        // 异步执行
        setTimeout(() => {
            try {
                onRejected(this.value)
            } catch (error) {
                onRejected(error)
            }
        })
    }
    

    5 promise的pending状态处理

    先看原生promise:

    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("原生done")
        }, 1000)
    }).then(value => {
        console.log(value)
    })
    console.log("同步代码")
    

    原生执行结果:先打印 "同步代码",1秒后打印 "原生done"

    但目前自定义then方法无法处理pending时的状态,不会打印setTimeout里的resolve结果。因为实例化完PM对象之后,立刻就执行了then方法。但是resolve改变状态是在1秒以后。

    查找并理解问题原因,在then方法里打印this值:

    then(onFulfilled, onRejected) {
        // 打印this,为了查看问题
        console.log(this)
        ...
    }
    

    此时执行测试代码:

    <script>
    let p = new PM((resolve, reject) => {
       setTimeout(()=>{
           resolve("自定义done")
       },1000)
    }).then(value => {
    console.log("resolve", value)
    })
    </script>
    

    测试结果:

    手写promise实现过程

    1秒后状态变为解决:

    手写promise实现过程

    所以如果测试代码的状态改变是异步的,但自定义class的方法还没有对此进行处理,现在修改方法:

    class PM {
        ...
        constructor(executor) {
            this.status = PM.PENDING;
            this.value = null;
            // 1.在构造函数中添加callbacks来保存pending状态时处理函数,当状态改变时循环调用
            this.callbacks = [];
            try {
                executor(this.resolve.bind(this), this.reject.bind(this))
            } catch (error) {
                this.reject(error)
            }
        }
        // 3.resovle与reject中添加处理callback方法的代码
        resolve(value) {
            if (this.status === PM.PENDING) {
                this.status = PM.FULFILLED;
                this.value = value;
                // 1秒后,状态变为解决或拒绝,从回调数组里取出函数执行
                this.callbacks.map(callback => callback.onFulfilled(value))
            }
        }
    
        reject(reason) {
            if (this.status === PM.PENDING) {
                this.status = PM.REJECTED;
                this.value = reason;
                // 1秒后,状态变为解决或拒绝,从回调数组里取出函数执行
                this.callbacks.map(callback => callback.onRejected(reason))
            }
        }
    
        then(onFulfilled, onRejected) {
            if (typeof onFulfilled !== "function") {
                onFulfilled = () => { }
            }
            if (typeof onRejected !== "function") {
                onRejected = () => { }
            }
            // 状态为等待时,定时器时间没到还没执行,此时先把函数压入回调数组,等到时机到了再取出执行
            if (this.status === PM.PENDING) {
                // 2.添加保存执行函数到callbacks数组中
                this.callbacks.push({ onFulfilled, onRejected })
            }
            ...
        }
    }
    

    6 pending状态异常处理

    测试代码:

    <script>
    let p = new PM((resolve, reject) => {
       setTimeout(()=>{
           resolve("自定义done")
       },1000)
    }).then(value => {
    console.log("resolve", abc)
    })
    </script>
    

    结果报错:

    手写promise实现过程

    给then方法里的pending状态添加错误处理:

    if (this.status === PM.PENDING) {
        this.callbacks.push({
            // 这个onFulfilled是属性名,value是上面resolve方法里执行回调时传进来的值
            onFulfilled: value => {
                try {
                    // 这个onFulfilled是then传进来的方法
                    onFulfilled(value)
                } catch (error) {
                    onRejected(error)
                }
            },
            onRejected: value => {
                try {
                    onRejected(value)
                } catch (error) {
                    onRejected(error)
                }
            }
        })
    }
    

    执行测试代码:

    <script>
    let p = new PM((resolve, reject) => {
       setTimeout(()=>{
           resolve("自定义done")
       },1000)
    }).then(value => {
    // 未定义的abc
    console.log("resolve", abc)
    },reason=>{
      console.log("reject",reason)
    })
    </script>
    

    测试结果:

    手写promise实现过程

    7 pending的异步任务处理技巧

    先看原生promise:

    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("原生done")
            console.log("定时器")
        }, 1000)
    }).then(value => {
        console.log(value)
    })
    console.log("同步代码")
    

    原生执行结果:

    手写promise实现过程

    此时相同的测试代码,自定义promise执行结果:

    手写promise实现过程

    原因:目前的方法,改变状态之后会立刻执行异步方法(也就是then里的resolve),这是不对的。promise的特性就是异步,then里面的函数需要异步执行,这样同步代码(console.log("定时器"))才不会等待它的执行,才能解决等待阻塞。

    修改class方法里的部分代码:

    resolve(value) {
        if (this.status === PM.PENDING) {
            this.status = PM.FULFILLED;
            this.value = value;
            // 将resolve执行通过setTimeout定义为异步任务
            // 先把它放到任务队列里,等同步的console.log("定时器")跑完之后,下一次再执行
            setTimeout(() => {
                this.callbacks.map(callback => callback.onFulfilled(value))
            })
        }
    }
    
    reject(reason) {
        if (this.status === PM.PENDING) {
            this.status = PM.REJECTED;
            this.value = reason;
            // 将reject执行通过setTimeout定义为异步任务
            setTimeout(() => {
                this.callbacks.map(callback => callback.onRejected(reason))
            })
        }
    }
    

    8 then链式操作原理分析

    Promise中的then是链式调用执行的,所以then也要返回Promise才能实现。

    1、then的onReject函数是对前面Promise的rejected的处理;

    2、但该Promise返回状态要为fulfilled,所以在调用onRejected后改变当前promise为fulfilled状态。

    先看原生promise:

    new Promise((resolve, reject) => {
        reject("原生fail")
    }).then(value => {
        console.log("1then:", value)
        return "1then 成功参数"
    }, reason => {
        console.log("1fail:", reason)
        return "1fail 失败参数"
    }).then(value => {
        console.log("2then:", value)
    }, reason => {
        console.log("2fail:", reason)
    })
    

    结果:

    手写promise实现过程

    注意点:

    每一个then返回的都是一个promise,且状态为解决,不论传给它的是resolve/reject。所以关键的是then方法要返回一个promise,修改代码如下:

    class PM {
        static PENDING = "pending";
        static FULFILLED = "fulfilled";
        static REJECTED = "rejected";
    
        constructor(executor) {
            this.status = PM.PENDING;
            this.value = null;
            this.callbacks = [];
            try {
                executor(this.resolve.bind(this), this.reject.bind(this))
            } catch (error) {
                this.reject(error)
            }
        }
    
        resolve(value) {
            if (this.status === PM.PENDING) {
                console.log("执行resolve方法")
                this.status = PM.FULFILLED;
                this.value = value;
                setTimeout(() => {
                    this.callbacks.map(callback => callback.onFulfilled(value))
                })
            }
        }
    
        reject(reason) {
            if (this.status === PM.PENDING) {
                console.log("执行reject方法")
                this.status = PM.REJECTED;
                this.value = reason;
                setTimeout(() => {
                    this.callbacks.map(callback => callback.onRejected(reason))
                })
            }
        }
    
        then(onFulfilled, onRejected) {
            console.log("执行then", this)
            if (typeof onFulfilled !== "function") {
                onFulfilled = () => { }
            }
            if (typeof onRejected !== "function") {
                onRejected = () => { }
            }
            // 返回一个promise
            return new PM((resolve, reject) => {
                if (this.status === PM.PENDING) {
                    console.log("执行this.status === PM.PENDING")
                    this.callbacks.push({
                        onFulfilled: value => {
                            try {
                                onFulfilled(value)
                            } catch (error) {
                                onRejected(error)
                            }
                        },
                        onRejected: value => {
                            try {
                                onRejected(value)
                            } catch (error) {
                                onRejected(error)
                            }
                        }
                    })
                }
                if (this.status === PM.FULFILLED) {
                    console.log("执行this.status === PM.FULFILLED")
                    setTimeout(() => {
                        try {
                            onFulfilled(this.value)
                        } catch (error) {
                            onRejected(error)
                        }
                    })
                }
                if (this.status === PM.REJECTED) {
                    console.log("执行this.status === PM.REJECTED")
                    setTimeout(() => {
                        try {
                            onRejected(this.value)
                        } catch (error) {
                            onRejected(error)
                        }
                    })
                }
            })
        }
    }
    

    测试代码:

    let p = new PM((resolve, reject) => {
        reject("自定义fail")
    }).then(value => {
        console.log("1then:", value)
        return "1then 成功参数"
    }, reason => {
        console.log("1fail:", reason)
        return "1fail 失败参数"
    }).then(value => {
        console.log("2then:", value)
    }, reason => {
        console.log("2fail:", reason)
    })
    

    结果:

    手写promise实现过程

    虽然then返回了promise,但是第二个then没有执行,还没有实现链式调用。

    原因:第一个then返回的promise是pending状态,没有改变新promise状态为resolve/reject,故而value是构造函数里定义的null。由于没有去改变状态,所以不会执行then方法。

    所以如果then返回的是Promise,需要判断分别处理返回值为Promise与普通值的情况。修改then代码实现不同类型不同处理机制:

    then(onFulfilled, onRejected) {
        ...
        return new PM((resolve, reject) => {
            if (this.status === PM.PENDING) {
                console.log("执行this.status === PM.PENDING")
                this.callbacks.push({
                    onFulfilled: value => {
                        try {
                            // 状态变为解决
                            let result = onFulfilled(value)
                            resolve(result) 
                        } catch (error) {
                            onRejected(error)
                        }
                    },
                    onRejected: value => {
                        try {
                            // 状态变为解决
                            let result = onRejected(value)
                            resolve(result)
                        } catch (error) {
                            onRejected(error)
                        }
                    }
                })
            }
            if (this.status === PM.FULFILLED) {
                console.log("执行this.status === PM.FULFILLED")
                setTimeout(() => {
                    try {
                        // 状态变为解决
                        let result = onFulfilled(this.value)
                        resolve(result) 
                    } catch (error) {
                        onRejected(error)
                    }
                })
            }
            if (this.status === PM.REJECTED) {
                console.log("执行this.status === PM.REJECTED")
                setTimeout(() => {
                    try {
                        // then返回的propmise状态一律为解决
                        let result = onRejected(this.value)
                        resolve(result) 
                    } catch (error) {
                        onRejected(error)
                    }
                })
            }
        })
    }
    

    测试代码:

    let p = new PM((resolve, reject) => {
        resolve("自定义done")
    }).then(value => {
        console.log("1then:", value)
        return "1then 成功参数"
    }, reason => {
        console.log("1fail:", reason)
        return "1fail 失败参数"
    }).then(value => {
        console.log("2then:", value)
    }, reason => {
        console.log("2fail:", reason)
    })
    

    结果:

    手写promise实现过程

    9 then新增promise异常处理

    原理:所有then里面的出错都交给最后一次then方法的reject函数处理。

    return new PM((resolve, reject) => {
        if (this.status === PM.PENDING) {
            this.callbacks.push({
                onFulfilled: value => {
                    try {
                        let result = onFulfilled(value)
                        resolve(result)
                    } catch (error) {
                        reject(error)
                        // onRejected(error)
                    }
                },
                onRejected: value => {
                    try {
                        let result = onRejected(value)
                        resolve(result)
                    } catch (error) {
                        reject(error)
                        // onRejected(error)
                    }
                }
            })
        }
        if (this.status === PM.FULFILLED) {
            setTimeout(() => {
                try {
                    let result = onFulfilled(this.value)
                    resolve(result)
                } catch (error) {
                    reject(error)
                    // onRejected(error)
                }
            })
        }
        if (this.status === PM.REJECTED) {
            setTimeout(() => {
                try {
                    let result = onRejected(this.value)
                    resolve(result)
                } catch (error) {
                    reject(error)
                    // onRejected(error)
                }
            })
        }
    })
    

    10 实现then的穿透传递

    先看原生:

    new Promise((resolve, reject) => {
        resolve("原生done")
    })
    .then()
    .then(value => {
        console.log(value)
    }, reason => {
        console.log(reason)
    })
    

    原生结果:

    手写promise实现过程

    而自定义的是undefined,此时还没有实现then的透传能力。修改then方法:

    if (typeof onFulfilled !== "function") {
        // then传进来的方法为空时,把值返回出去
        onFulfilled = () => this.value
    }
    if (typeof onRejected !== "function") {
        // then传进来的方法为空时,把值返回出去
        onRejected = () => this.value
    }
    

    11 then返回promise的处理

    先看原生:

    new Promise((resolve, reject) => {
        resolve("原生done")
    })
    .then(value => {
        return new Promise((resolve) => {
            resolve("返回的值")
        })
    })
    .then(value => {
        console.log(value)
    })
    

    原生执行结果:

    手写promise实现过程

    而同样的测试,自定义方法结果为:

    手写promise实现过程

    需要拿到返回的promise返回的值,而不是它本身。修改代码:

    return new PM((resolve, reject) => {
        if (this.status === PM.PENDING) {
            this.callbacks.push({
                onFulfilled: value => {
                    try {
                        let result = onFulfilled(value)
                        // 增加返回结果的判断
                        if (result instanceof PM) {
                            result.then(resolve, reject)
                        } else {
                            resolve(result)
                        }
                    } catch (error) {
                        reject(error)
                    }
                },
                onRejected: value => {
                    try {
                        let result = onRejected(value)
                        // 增加返回结果的判断
                        if (result instanceof PM) {
                            result.then(resolve, reject)
                        } else {
                            resolve(result)
                        }
                    } catch (error) {
                        reject(error)
                    }
                }
            })
        }
        if (this.status === PM.FULFILLED) {
            setTimeout(() => {
                try {
                    let result = onFulfilled(this.value)
                    // 增加返回结果的判断
                    if (result instanceof PM) {
                        // 若是promise,则调用then方法获取它的值,并传给return的new promise(下一个)的resolve/reject
                        result.then(resolve, reject)
                        // 注释代码为优化前,优化原理见下面测试代码注释
                        // result.then(value => {
                        //     resolve(value)
                        // }, reason => {
                        //     reject(reason)
                        // })
                    } else {
                        resolve(result)
                    }
                } catch (error) {
                    reject(error)
                }
            })
        }
        if (this.status === PM.REJECTED) {
            setTimeout(() => {
                try {
                    let result = onRejected(this.value)
                    // 增加返回结果的判断
                    if (result instanceof PM) {
                        result.then(resolve, reject)
                    } else {
                        resolve(result)
                    }
                } catch (error) {
                    reject(error)
                }
            })
        }
    })
    

    测试代码:

    1 new PM((resolve, reject) => {
    2   resolve("自定义done")
    3 })
    4 .then(value => {
        // 这个promise调用上一个promise的两个函数,来改变状态,然后传给下一个then
        // 核心就是在这个promise的then里把4的then的promise状态改掉
        return new PM((resolve) => {
            resolve("返回的值")
        })
    })
    .then(value => {
        console.log(value)
    })
    

    现在发现pendding、fulfilled、rejected 状态的代码非常相似,所以可以提取出方法Parse来复用。代码优化后:

    class PM {
        static PENDING = "pending";
        static FULFILLED = "fulfilled";
        static REJECTED = "rejected";
    
        constructor(executor) {
            this.status = PM.PENDING;
            this.value = null;
            this.callbacks = [];
            try {
                executor(this.resolve.bind(this), this.reject.bind(this))
            } catch (error) {
                this.reject(error)
            }
        }
    
        resolve(value) {
            if (this.status === PM.PENDING) {
                this.status = PM.FULFILLED;
                this.value = value;
                setTimeout(() => {
                    this.callbacks.map(callback => {
                        callback.onFulfilled(value)
                    })
                })
            }
        }
    
        reject(reason) {
            if (this.status === PM.PENDING) {
                this.status = PM.REJECTED;
                this.value = reason;
                setTimeout(() => {
                    this.callbacks.map(callback => callback.onRejected(reason))
                })
            }
        }
    
        then(onFulfilled, onRejected) {
            if (typeof onFulfilled !== "function") {
                onFulfilled = () => this.value
            }
            if (typeof onRejected !== "function") {
                onRejected = () => this.value
            }
            return new PM((resolve, reject) => {
                if (this.status === PM.PENDING) {
                    this.callbacks.push({
                        onFulfilled: value => {
                        	// 优化
                            this.parse(onFulfilled(value), resolve, reject)
                        },
                        onRejected: value => {
                        	// 优化
                            this.parse(onRejected(value), resolve, reject)
                        }
                    })
                }
                if (this.status === PM.FULFILLED) {
                    setTimeout(() => {
                    	// 优化
                        this.parse(onFulfilled(this.value), resolve, reject)
                    })
                }
                if (this.status === PM.REJECTED) {
                    setTimeout(() => {
                        // 优化
                        this.parse(onRejected(this.value), resolve, reject)
                    })
                }
            })
        }
        // 抽取通用方法,几处调用只有传进来的result不同,其它都相同
        parse(result, resolve, reject) {
            try {
                if (result instanceof PM) {
                    result.then(resolve, reject)
                } else {
                    resolve(result)
                }
            } catch (error) {
                reject(error)
            }
        }
    }
    

    12 promise返回类型约束

    先看原生:

    let promise = new Promise((resolve, reject) => {
        resolve("原生done")
    })
    let p = promise.then(value => {
        // 由于这部分是异步执行,已经生成了p,可以打印p
        console.log("p", p)
    })
    console.log("同步代码")
    

    原生输出结果:

    手写promise实现过程

    then返回的promise不能是then相同的Promise,也就是不允许返回自己生成的promise对象。执行以下示例代码将产生错误:

    let promise = new Promise((resolve, reject) => {
        resolve("原生done")
    })
    let p = promise.then(value => {
        // 这里返回本身自己,不允许
        return p
    })
    console.log("同步代码")
    

    报错:

    手写promise实现过程

    但是目前自定义的promise不具有这个特性,不会报错。要得到和原生一样的效果,需要添加当前promise作为parse的第一个参数与函数结果比对:

    then(onFulfilled, onRejected) {
        if (typeof onFulfilled !== "function") {
            onFulfilled = () => this.value
        }
        if (typeof onRejected !== "function") {
            onRejected = () => this.value
        }
        // 不直接返回,定义一个变量
        let promise = new PM((resolve, reject) => {
            if (this.status === PM.PENDING) {
                this.callbacks.push({
                    onFulfilled: value => {
                        // 增加入参promise,由于异步执行,所以可读取到上面定义的promise
                        this.parse(promise, onFulfilled(value), resolve, reject)
                    },
                    onRejected: value => {
                        // 增加入参promise
                        this.parse(promise, onRejected(value), resolve, reject)
                    }
                })
            }
            if (this.status === PM.FULFILLED) {
                setTimeout(() => {
                    // 增加入参promise
                    this.parse(promise, onFulfilled(this.value), resolve, reject)
                })
            }
            if (this.status === PM.REJECTED) {
                setTimeout(() => {
                    // 增加入参promise
                    this.parse(promise, onRejected(this.value), resolve, reject)
                })
            }
        })
        // 在这里返回变量
        return promise
    }
    
    parse(promise, result, resolve, reject) {
        // 增加判断,相等则报错
        if (promise === result) {
            throw new TypeError("Chaining cycle detected")
        }
        try {
            if (result instanceof PM) {
                result.then(resolve, reject)
            } else {
                resolve(result)
            }
        } catch (error) {
            reject(error)
        }
    }
    

    13 实现resolve与reject

    实现promise静态方法:

    Promise.resolve("原生done").then(value => {
        console.log(value)
    })
    Promise.reject("原生fail").then(null, reason => {
        console.log(reason)
    })
    

    在自定class里增加静态方法,核心是返回一个promise:

    static resolve(value) {
        return new PM((resolve, reject) => {
            // 需要改变promise状态,不然then不会对它进行处理
            resolve(value)
        })
    }
    

    再看原生,如果传入的是promise,那么这个promise状态决定了then执行哪一个方法,resolve走成功方法,reject走失败方法。

    let p = new Promise((resolve, reject) => {
        reject("原生fail1")
    })
    Promise.resolve(p).then(value => {
        console.log("成功", value)
    }, reason => {
        console.log("失败", reason)
    })
    

    原生结果:

    手写promise实现过程

    再次修改刚才的静态方法,顺便加上reject:

    static resolve(value) {
        return new PM((resolve, reject) => {
            if (value instanceof PM) {
                value.then(resolve, reject)
            } else {
                resolve(value)
            }
        })
    }
    static reject(value) {
        return new PM((resolve, reject) => {
            reject(value)
        })
    }
    

    14 promise的all方法实现

    先看原生:

    let p1 = new Promise((resolve, reject) => {
        resolve("原生p1")
    })
    let p2 = new Promise((resolve, reject) => {
        resolve("原生p2")
    })
    Promise.all([p1, p2]).then(value => {
        console.log(value)
    }, reason => {
        console.log(reason)
    })
    // 输出 ["原生p1", "原生p2"]
    
    // 有任何一个reject就走到reject,只取第一个reject
    let p1 = new Promise((resolve, reject) => {
        resolve("原生p1")
    })
    let p2 = new Promise((resolve, reject) => {
        reject("原生p2")
    })
    Promise.all([p1, p2]).then(value => {
        console.log(value)
    }, reason => {
        console.log(reason)
    })
    // 输出 原生p2
    

    自定义方法实现,在class里添加静态方法:

    static all(promises) {
        return new PM((resolve, reject) => {
            const values = [];
            promises.forEach(promise => {
                promise.then(value => {
                    values.push(value)
                    // 全部成功才resolve
                    if (values.length === promises.length) {
                        resolve(values)
                    }
                }, reason => {
                    // 只要有一个失败就reject
                    reject(reason)
                })
            })
        })
    }
    

    15 promise的race静态方法实现

    先看原生:

    let p1 = new Promise((resolve, reject) => {
        setTimeout(() => {
            reject("原生p1")
        }, 2000)
    })
    let p2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            reject("原生p2")
        }, 1000)
    })
    Promise.race([p1, p2]).then(value => {
        console.log(value)
    }, reason => {
        console.log(reason)
    })
    // 谁快用谁。输出 原生p2
    

    自定义实现,在class里添加静态方法:

    static race(promises) {
        return new PM((resolve, reject) => {
            promises.map(promise => {
               // 状态一旦改变就不会再执行了,所以达到了谁先用谁
                promise.then(value => {
                    resolve(value)
                }, reason => {
                    reject(reason)
                })
            })
        })
    }
    

    完整实现代码

    class PM {
        static PENDING = "pending";
        static FULFILLED = "fulfilled";
        static REJECTED = "rejected";
    
        constructor(executor) {
            this.status = PM.PENDING;
            this.value = null;
            this.callbacks = [];
            try {
                executor(this.resolve.bind(this), this.reject.bind(this))
            } catch (error) {
                this.reject(error)
            }
        }
    
        resolve(value) {
            if (this.status === PM.PENDING) {
                this.status = PM.FULFILLED;
                this.value = value;
                setTimeout(() => {
                    this.callbacks.map(callback => {
                        callback.onFulfilled(value)
                    })
                })
            }
        }
    
        reject(reason) {
            if (this.status === PM.PENDING) {
                this.status = PM.REJECTED;
                this.value = reason;
                setTimeout(() => {
                    this.callbacks.map(callback => callback.onRejected(reason))
                })
            }
        }
    
        then(onFulfilled, onRejected) {
            if (typeof onFulfilled !== "function") {
                onFulfilled = () => this.value
            }
            if (typeof onRejected !== "function") {
                onRejected = () => this.value
            }
            let promise = new PM((resolve, reject) => {
                if (this.status === PM.PENDING) {
                    this.callbacks.push({
                        onFulfilled: value => {
                            this.parse(promise, onFulfilled(value), resolve, reject)
                        },
                        onRejected: value => {
                            this.parse(promise, onRejected(value), resolve, reject)
                        }
                    })
                }
                if (this.status === PM.FULFILLED) {
                    setTimeout(() => {
                        this.parse(promise, onFulfilled(this.value), resolve, reject)
                    })
                }
                if (this.status === PM.REJECTED) {
                    setTimeout(() => {
                        this.parse(promise, onRejected(this.value), resolve, reject)
                    })
                }
            })
            return promise
        }
    
        parse(promise, result, resolve, reject) {
            if (promise === result) {
                throw new TypeError("Chaining cycle detected")
            }
            try {
                if (result instanceof PM) {
                    result.then(resolve, reject)
                } else {
                    resolve(result)
                }
            } catch (error) {
                reject(error)
            }
        }
    
        static resolve(value) {
            return new PM((resolve, reject) => {
                if (value instanceof PM) {
                    value.then(resolve, reject)
                } else {
                    resolve(value)
                }
            })
        }
        static reject(value) {
            return new PM((resolve, reject) => {
                reject(value)
            })
        }
        static all(promises) {
            return new PM((resolve, reject) => {
                const values = [];
                promises.forEach(promise => {
                    promise.then(value => {
                        values.push(value)
                        if (values.length === promises.length) {
                            resolve(values)
                        }
                    }, reason => {
                        reject(reason)
                    })
                })
            })
        }
        static race(promises) {
            return new PM((resolve, reject) => {
                promises.map(promise => {
                    promise.then(value => {
                        resolve(value)
                    }, reason => {
                        reject(reason)
                    })
                })
            })
        }
    }
    

    如有错误,请帮忙指正~

    参考教程:www.houdunren.com/Edu/video/1…


    起源地下载网 » 手写promise实现过程

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元