Promise从入门到手写 | [Promise系列一](二)

简介: Promise从入门到手写 | [Promise系列一](二)

手写Promise


代码逐步迭代,可以对照着看,我把注释都写得比较清晰了~


构造函数实现


我们第一步首先就是完成Promise的构造函数,构造函数我们简单去想,其实就是接收一个执行器函数,执行器函数有两个参数,这个方法阔以改变Promise对象的状态和结果。ok,说干就干!


tips:

  1. 注意!throw err也可以修改Promise的状态与结果!
  2. promise的状态只能修改一次,需要做限制


// 万里长城第一步
function Promise(executor){
    this.promiseState = 'pending';
    this.promiseResult = null;
    const resolve = val => {
        // 状态只能修改一次
        if(this.promiseState !== 'pending') return;
        // 1. 要去修改Promise对象的状态([[promiseState]]),置为成功fulfilled
        this.promiseState = 'fulfilled';
        // 2. 要去修改Promise对象的状态([[promiseResult]])
        this.promiseResult = val;
    }
    const reject = err => {
        // 状态只能修改一次
        if(this.promiseState !== 'pending') return;
        // 1. 要去修改Promise对象的状态([[promiseState]]),置为失败rejected
        this.promiseState = 'rejected';
        // 2. 要去修改Promise对象的状态([[promiseResult]])
        this.promiseResult = err;
    }
    // 为什么要加try catch 是因为,throw err也相当于调用reject了【前面说过没看过的去补课】
    try{
        /*
        * 同步执行执行器函数
        * 执行器函数接收两个参数,一个是resolve,一个是reject
        */
        executor(resolve,reject);
    } catch(err) {
        reject(err);
    }
}


then方法的实现


首先按照之前说过的,then支持两个参数,分别是成功和失败的回调,而且这两个参数可传可不传。


其次,因为异步任务的问题,并且支持多个回调,所以我们需要对回调函数采用数组进行存储,所以引入了新的变量,callbackList

而且我们需要注意then的返回结果也是Promise对象【不记得的话,回头看看~】


// 万里长城今犹在~
function Promise(executor){
    //保存promise状态
    this.promiseState = 'pending';
    //保存promise结果
    this.promiseResult = null;
    //用于保存异步回调函数列表
    this.callbackList = [];
    const resolve = val => {
        // 状态只能修改一次
        if(this.promiseState !== 'pending') return;
        // 1. 要去修改Promise对象的状态([[promiseState]]),置为成功fulfilled
        this.promiseState = 'fulfilled';
        // 2. 要去修改Promise对象的状态([[promiseResult]])
        this.promiseResult = val;
        // 调用成功的回调【callbackList存起来的】
        for(let callback of this.callbackList){
            callback.onResolved(val);
        }
    }
    const reject = err => {
        // 状态只能修改一次
        if(this.promiseState !== 'pending') return;
        // 1. 要去修改Promise对象的状态([[promiseState]]),置为失败rejected
        this.promiseState = 'rejected';
        // 2. 要去修改Promise对象的状态([[promiseResult]])
        this.promiseResult = err;
        // 调用失败的回调【callbackList存起来的】
        for(let callback of this.callbackList){
            callback.onRejected(err);
        }
    }
    // 为什么要加try catch 是因为,throw err也相当于调用reject了【前面说过没看过的去补课】
    try{
        /*
        * 同步执行执行器函数
        * 执行器函数接收两个参数,一个是resolve,一个是reject
        */
        executor(resolve,reject);
    } catch(err) {
        reject(err);
    }
}
//then方法
Promise.prototype.then = function(onResolved,onRejected){
    const self = this;
    // then方法会返回Promise
    return new Promise((resolve,reject) => {
        // 对返回值的处理进行封装
        const handleCallback = (callback) => {
            // 如果回调函数中抛出错误,则reject
            try{
                // 需要依据回调的返回结果确定then方法的返回值
                // 现在的this会指向return的promise对象,所以使用self
                const res = callback(self.promiseResult);
                if(res instanceof Promise){
                    //如果回调返回结果是个Promise
                    res.then(val => {
                        resolve(val);
                    },err => {
                        reject(err);
                    })
                }else{
                    // 返回结果不是Promise
                    resolve(res);
                }
            }catch(err){
                reject(err);
            }
        }
        //调用回调函数
        if(this.promiseState === 'fulfilled'){
            handleCallback(onResolved);
        }
        if(this.promiseState === 'rejected'){
            handleCallback(onRejected);
        }
        /*
        * 如果是pending状态,则异步任务,在改变状态的时候去调用回调函数
        * 所以要保存回调函数
        * 因为promise实例阔以指定多个回调,于是采用数组 
        */
        if(this.promiseState === 'pending'){
            this.callbackList.push({
                onResolved:() => {
                    handleCallback(onResolved); 
                },
                onRejected:() => {
                    handleCallback(onRejected);
                }
            })
        }
    })
}


catch方法的实现


我们采用then方法去实现catch方法,但是catch可以处理异常穿透【前面又说哦~】


// 我想找人陪我去长城玩,哈哈哈哈
function Promise(executor){
    //保存promise状态
    this.promiseState = 'pending';
    //保存promise结果
    this.promiseResult = null;
    //用于保存异步回调函数列表
    this.callbackList = [];
    const resolve = val => {
        // 状态只能修改一次
        if(this.promiseState !== 'pending') return;
        // 1. 要去修改Promise对象的状态([[promiseState]]),置为成功fulfilled
        this.promiseState = 'fulfilled';
        // 2. 要去修改Promise对象的状态([[promiseResult]])
        this.promiseResult = val;
        // 调用成功的回调【callbackList存起来的】
        for(let callback of this.callbackList){
            callback.onResolved(val);
        }
    }
    const reject = err => {
        // 状态只能修改一次
        if(this.promiseState !== 'pending') return;
        // 1. 要去修改Promise对象的状态([[promiseState]]),置为失败rejected
        this.promiseState = 'rejected';
        // 2. 要去修改Promise对象的状态([[promiseResult]])
        this.promiseResult = err;
        // 调用失败的回调【callbackList存起来的】
        for(let callback of this.callbackList){
            callback.onRejected(err);
        }
    }
    // 为什么要加try catch 是因为,throw err也相当于调用reject了【前面说过没看过的去补课】
    try{
        /*
        * 同步执行执行器函数
        * 执行器函数接收两个参数,一个是resolve,一个是reject
        */
        executor(resolve,reject);
    } catch(err) {
        reject(err);
    }
}
//then方法
Promise.prototype.then = function(onResolved,onRejected){
    const self = this;
    //处理异常穿透 并且为onResolved,onRejected设置默认值。因为这两个参数可以都不传
    if(typeof onRejected !== 'function'){
        onRejected = err => {
            throw err;
        }
    }
    if(typeof onResolved !== 'function'){
        onResolved = val => val;
    }
    // then方法会返回Promise
    return new Promise((resolve,reject) => {
        // 对返回值的处理进行封装
        const handleCallback = (callback) => {
            // 如果回调函数中抛出错误,则reject
            try{
                // 需要依据回调的返回结果确定then方法的返回值
                // 现在的this会指向return的promise对象,所以使用self
                const res = callback(self.promiseResult);
                if(res instanceof Promise){
                    //如果回调返回结果是个Promise
                    res.then(val => {
                        resolve(val);
                    },err => {
                        reject(err);
                    })
                }else{
                    // 返回结果不是Promise
                    resolve(res);
                }
            }catch(err){
                reject(err);
            }
        }
        //调用回调函数
        if(this.promiseState === 'fulfilled'){
            handleCallback(onResolved);
        }
        if(this.promiseState === 'rejected'){
            handleCallback(onRejected);
        }
        /*
        * 如果是pending状态,则异步任务,在改变状态的时候去调用回调函数
        * 所以要保存回调函数
        * 因为promise实例阔以指定多个回调,于是采用数组 
        */
        if(this.promiseState === 'pending'){
            this.callbackList.push({
                onResolved:() => {
                    handleCallback(onResolved); 
                },
                onRejected:() => {
                    handleCallback(onRejected);
                }
            })
        }
    })
}
//catch方法
Promise.prototype.catch = function(onRejected) {
    //  我们可以直接使用then方法实现
    return this.then(undefined,onRejected);
}


Promise.resolve方法实现


简单了,不说啥了


//resolve方法
Promise.resolve = function(val) {
    //返回值的情况在前文说过,可以在 Promise的使用一章找到
    return new Promise((resolve,reject)=>{
        if(val instanceof Promise){
            val.then(val => {
                resolve(val);
            }, err => {
                reject(err);
            });
        }else{
            resolve(value);
        }
    }) 
}


Promise.reject方法实现


更加简单了,不说啥了


//reject方法
Promise.reject = function(err) {
    //返回值的情况在前文说过,可以在 Promise的使用一章找到
    return new Promise((resolve,reject)=>{
        reject(err);
    }) 
}


Promise.all方法实现


比较简单,回顾之前Promise.all的用法以及返回值,就阔以看懂~


//可以先去回顾一下all方法的用法
//all
Promise.all = function(promiseList) {
    let count = 0;
    let res = [];
    const length = promiseList.length;
    return new Promise((resolve,reject)=>{
        for(let i = 0;i < length; i++){
            promiseList[i].then(val => {
                count++;
                res[i] = val;
                if(count === length){
                    resolve(res);
                }
            },err => {
                reject(err);
            });
        }
    }) 
}


Promise.race方法实现


比较简单,回顾之前Promise.race的用法以及返回值,就阔以看懂~


//race
//要结束了!
Promise.race = function(promiseList) {
    const length = promiseList.length;
    //谁先完成谁就决定结果!
    return new Promise((resolve,reject)=>{
        for(let i = 0;i < length; i++){
            promiseList[i].then(val => {
                resolve(val);
            },err => {
                reject(err);
            });
        }
    }) 
}


完整代码以及细节处理


tips: 细节回调函数是异步的 我们使用setTimeout进行包裹


function Promise(executor){
    //保存promise状态
    this.promiseState = 'pending';
    //保存promise结果
    this.promiseResult = null;
    //用于保存异步回调函数列表
    this.callbackList = [];
    const resolve = val => {
        // 状态只能修改一次
        if(this.promiseState !== 'pending') return;
        // 1. 要去修改Promise对象的状态([[promiseState]]),置为成功fulfilled
        this.promiseState = 'fulfilled';
        // 2. 要去修改Promise对象的状态([[promiseResult]])
        this.promiseResult = val;
        setTimeout(() => {
            // 调用成功的回调【callbackList存起来的】
            for(let callback of this.callbackList){
                callback.onResolved(val);
            }
        })
    }
    const reject = err => {
        // 状态只能修改一次
        if(this.promiseState !== 'pending') return;
        // 1. 要去修改Promise对象的状态([[promiseState]]),置为失败rejected
        this.promiseState = 'rejected';
        // 2. 要去修改Promise对象的状态([[promiseResult]])
        this.promiseResult = err;
        setTimeout(() => {
            // 调用失败的回调【callbackList存起来的】
            for(let callback of this.callbackList){
                callback.onRejected(err);
            }
        })
    }
    // 为什么要加try catch 是因为,throw err也相当于调用reject了【前面说过没看过的去补课】
    try{
        /*
        * 同步执行执行器函数
        * 执行器函数接收两个参数,一个是resolve,一个是reject
        */
        executor(resolve,reject);
    } catch(err) {
        reject(err);
    }
}
//then方法
Promise.prototype.then = function(onResolved,onRejected){
    const self = this;
    //处理异常穿透 并且为onResolved,onRejected设置默认值。因为这两个参数可以都不传
    if(typeof onRejected !== 'function'){
        onRejected = err => {
            throw err;
        }
    }
    if(typeof onResolved !== 'function'){
        onResolved = val => val;
    }
    // then方法会返回Promise
    return new Promise((resolve,reject) => {
        // 对返回值的处理进行封装
        const handleCallback = (callback) => {
            // 如果回调函数中抛出错误,则reject
            try{
                // 需要依据回调的返回结果确定then方法的返回值
                // 现在的this会指向return的promise对象,所以使用self
                const res = callback(self.promiseResult);
                if(res instanceof Promise){
                    //如果回调返回结果是个Promise
                    res.then(val => {
                        resolve(val);
                    },err => {
                        reject(err);
                    })
                }else{
                    // 返回结果不是Promise
                    resolve(res);
                }
            }catch(err){
                reject(err);
            }
        }
        //调用回调函数
        if(this.promiseState === 'fulfilled'){
            setTimeout(()=>{
                handleCallback(onResolved);
            })
        }
        if(this.promiseState === 'rejected'){
            setTimeout(()=>{
                handleCallback(onRejected);
            })
        }
        /*
        * 如果是pending状态,则异步任务,在改变状态的时候去调用回调函数
        * 所以要保存回调函数
        * 因为promise实例阔以指定多个回调,于是采用数组 
        */
        if(this.promiseState === 'pending'){
            this.callbackList.push({
                onResolved:() => {
                    handleCallback(onResolved); 
                },
                onRejected:() => {
                    handleCallback(onRejected);
                }
            })
        }
    })
}
//catch方法
Promise.prototype.catch = function(onRejected) {
    //  我们可以直接使用then方法实现
    return this.then(undefined,onRejected);
}
//resolve方法
Promise.resolve = function(val) {
    //返回值的情况在前文说过,可以在 Promise的使用一章找到
    return new Promise((resolve,reject)=>{
        if(val instanceof Promise){
            val.then(val => {
                resolve(val);
            }, err => {
                reject(err);
            });
        }else{
            resolve(value);
        }
    }) 
}
//reject方法
Promise.reject = function(err) {
    //返回值的情况在前文说过,可以在 Promise的使用一章找到
    return new Promise((resolve,reject)=>{
        reject(err);
    }) 
}
//all
Promise.all = function(promiseList) {
    let count = 0;
    let res = [];
    const length = promiseList.length;
    return new Promise((resolve,reject)=>{
        for(let i = 0;i < length; i++){
            promiseList[i].then(val => {
                count++;
                res[i] = val;
                if(count === length){
                    resolve(res);
                }
            },err => {
                reject(err);
            });
        }
    }) 
}
//race
Promise.race = function(promiseList) {
    const length = promiseList.length;
    //谁先完成谁就决定结果!
    return new Promise((resolve,reject)=>{
        for(let i = 0;i < length; i++){
            promiseList[i].then(val => {
                resolve(val);
            },err => {
                reject(err);
            });
        }
    }) 
}


至此,我们手写Promise的章节也就结束了~


结束语


tips:其实我真的很想吐槽自己,为什么老是在博客结尾要么打鸡血,要么说鸡汤,哈哈


Promise一词本意是承诺。我以这篇文章作为我新的开始,从基础开始沉淀,拒绝好高骛远。


我承诺我的信念与追求会始终如一

我承诺会让自己看遍世间美景

我承诺我我会一直努力成为优秀的工程师

我承诺无论结果如何,喜欢的都会努力地勇敢地追求,不留遗憾

...

最后,愿老朽我永远热血,愿世界永远和平

伙伴们葱呀

相关文章
|
5月前
|
前端开发 JavaScript
Promise入门/面试必看
Promise入门/面试必看
44 0
|
前端开发 JavaScript API
|
前端开发 API 容器
ES6入门之Promise
ES6入门之Promise
|
前端开发
Promise对象简单入门
Promise对象简单入门
Promise对象简单入门
|
存储 前端开发 JavaScript
Promise从入门到手写 | [Promise系列一](一)
Promise从入门到手写 | [Promise系列一](一)
113 0
|
1月前
|
前端开发 JavaScript
如何处理 JavaScript 中的异步操作和 Promise?
如何处理 JavaScript 中的异步操作和 Promise?
15 1
|
1月前
|
前端开发 JavaScript
在JavaScript中,什么是promise、怎么使用promise、怎么手写promise
在JavaScript中,什么是promise、怎么使用promise、怎么手写promise
23 4
|
27天前
|
前端开发 JavaScript 开发者
JavaScript 中的异步编程:Promise 和 Async/Await
在现代的 JavaScript 开发中,异步编程是至关重要的。本文将介绍 JavaScript 中的异步编程概念,重点讨论 Promise 和 Async/Await 这两种常见的处理异步操作的方法。通过本文的阐述,读者将能够更好地理解和应用这些技术,提高自己在 JavaScript 开发中处理异步任务的能力。
|
2月前
|
前端开发 JavaScript API
JavaScript学习笔记(一)promise与async
JavaScript学习笔记(一)promise与async