您的当前位置:首页正文

前端 面试----手写promise(promise自定义封装)

2024-11-23 来源:个人技术集锦

Promise函数的基本了解

----------简单来说,promise函数是为了解决异步回调时的一些问题,更准确来说是为了解决我们在开发中,经常会面临的“回调地狱”所给开发者带来的困扰。promise可以被理解成一个方案,来有助于我们快速规避这些麻烦,从而提高我们的开发效率。

----------我们知道一个Promise函数的状态必然处于以下几种状态中的一个:

为什么要使用Promise

----指定回调函数的方式更加灵活

旧的:必须在启动异步任务前指定

promise:启动异步任务=》返回promise对象=》给promise对象绑定回调函数(甚至可以在异步任务)

----支持链式调用,可以解决回调地狱问题

那什么是回调地狱---》回调函数调用,外部回调函数异步执行的结果是嵌套的回调执行的条件,其缺点不方便阅读,不便于异常处理,解决方案是promise链式调用。

promise内置的几种方法

既然我们知道了promise的作用之后,我们就来谈谈promise函数所内置的几个API,也就是方法,这些方法在我们往后的学习和工作当中会被反复的使用,因此要熟悉这些API能实现的功能变的尤为重要:

  • resolve:promise构造函数上挂载或在内部定义的方法,表示一个“成功”时的状态,且此状态一旦生成就不可逆,此过程也称为“敲定”了这个状态。

  • reject:promise构造函数上挂载或在内部定义的方法,表示一个“失败”时的状态,且此状态一旦生成就不可逆,此过程也称为“敲定”了这个状态。

  • then:promise.then方法返回的结果也是一个promise函数,准确来说是一个对象,这个对象中有then方法返回的promise对象及其所处的状态和结果值等,因此这个新对象也可以使用promise所内置的方法。

  • catch:catch在promise中经常用来快速捕捉异常,例如捕捉throw抛错时而导致的非正常状态,在自定义封装中我们用try ...catch来搭配使用,catch返回值是一个失败的promise对象。

  • all: promise中all方法的参数接受一个数组,这个数组的成员要满足都为promise对象。如果所有的promise对象状态都为“fulfilled”,也就是成功,all方法返回一个状态也为成功的promise对象,此对象内部的结果值为此成功的数组。若有一个promise成员的状态为失败,那么all方法就会返回一个失败的promise对象,其状态为"rejected",其内部结果值为这个数组中失败的promise函数的结果值。

  • race: promise中race方法的参数接受一个数组,这个数组的成员要满足都为promise对象,race方法返回一个promise对-象,这个对象的状态由数组中第一个状态改变的promise函数决定,且两个对象的状态保持一致,且其结果值为数组中第一个状态改变的promise函数的结果值。

Promise对象状态改变的三种方式

Promise.then()返回的新的promise的结果状态由什么决定?

简单表述:由then()指定的回调函数执行的结果决定

 

----Promise.reject

该方法将始终返回一个为失败的Promise对象,无论参数是否为Promise类型还是其他,最终都是放回失败的Promise。

----Promise下的resolve方法

作用:将一个普通的值转化为Promise类型的数据,

  分两种情况:

1.当resolve方法参数为非Promise对象,则返回的结果为成功的Promise对象

2.当resolve方法参数为Promise对象,则参数对象的状态和结果将直接影响最终resolve方法的

返回值的那个对象的状态和结果

--------finally

是ES9中新增的特性,表示无论Promise对象变成了fulfilled还是rejected状态,最终都会执行finally方法的回调函数参数是不接受参数的

html代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>promise.all</title>
    <style></style>
    <script src="./promise.js"></script>
</head>

<body>
    <script>
 // 欢迎来到 我的世界-

        // 基本格式
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('执行value')
                console.log(1);
            }, 100)
            console.log(2);

        })
        p.then(value=>{
            console.log(3);
        },reason=>{
            console.log(4);
        })

        console.log(5);
  </script>
</body>

</html>

js代码

// 定义promise构造函数
function Promise(executor) {
    // 设置默认状态和默认值
    this.PromiseState = 'pending'
    this.PromiseResult = null

    // 设置一个空数组,异步时调用
    this.callbacks = []

    // this赋给self
    const self = this

    // 成功时的函数
    function resolve(data) {
        // 判断此时的p的状态是否已经改变
        if (self.PromiseState !== 'pending') return

        // 设置实例成功时的状态和结果值
        self.PromiseState = 'fulfilled'
        self.PromiseResult = data

        // 执行调用函数为resolve的异步任务
        self.callbacks.forEach(item => {
            item.onResolved(data)
        })
    }

    // 失败时的函数
    function reject(data) {
        // 判断此时的p的状态是否已经改变
        if (self.PromiseState !== 'pending') return


        // 设置实例成功时的状态和结果值
        self.PromiseState = 'rejected'
        self.PromiseResult = data

        // 执行调用函数为reject的异步任务
        self.callbacks.forEach(item => {
            item.onRejected(data)
        })
    }


    // 执行函数并捕捉可能存在的异常
    try {
        executor(resolve, reject)
    } catch (e) {
        reject(e)
    }
}

// 在promise函数原型上挂载一个then方法
Promise.prototype.then = function (onResolved, onRejected) {
    const self = this
    // 若用户没有传入onResolved箭头函数
    if (typeof onResolved !== 'function') {
        onResolved = value => value
    }


    // 若用户没有传入onRejected箭头函数
    if (typeof onRejected !== 'function') {
        onRejected = resaon => {
            throw resaon
        }
    }


    return new Promise((resolve, reject) => {


        // 封装common函数
        function common(type) {
            try {
                // 执行函数,并且把执行结果赋值给result变量
                let result = type(self.PromiseResult)

                if (result instanceof Promise) {
                    result.then(v => {
                        resolve(v)
                    }, r => {
                        reject(r)
                    })
                } else {
                    resolve(result)
                }

            } catch (e) {
                reject(e)
            }
        }

        // 成功时的then
        if (this.PromiseState === 'fulfilled') {
            setTimeout(() => {
                common(onResolved)
            })
        }

        // 失败时的then
        if (this.PromiseState === 'rejected') {
            setTimeout(() => {
                common(onRejected);
            })

        }


        // 异步执行的then
        if (this.PromiseState === 'pending') {
            self.callbacks.push(
                {
                    onResolved: function (data) {
                        common(onResolved)
                    },

                    onRejected: function (data) {
                        common(onRejected)
                    }
                }
            )
        }
    })

}

// 给构造函数Promise挂载resolve函数
Promise.resolve = function (data) {
    return new Promise((resolve, reject) => {
        if (data instanceof Promise) {
            data.then(v => {
                resolve(v)
            }, r => {
                reject(r)
            })
        } else {
            resolve(data)
        }
    })
}


// 给构造函数Promise挂载reject函数
Promise.reject = function (data) {
    return new Promise((resolve, reject) => {
        reject(data)

    })
}

// 挂载catch方法
Promise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected)
}

// 挂载all方法
Promise.all = function (promises) {
    return new Promise((resolve, reject) => {
        let count = 0;
        let arr = []

        for (let i = 0; i < promises.length; i++) {
            promises[i].then(v => {
                count++;
                arr[i] = v

                if (count === promises.length) {
                    resolve(arr)
                }
            }, r => {
                reject(r)
            })
        }

    })
}

// 挂载race方法
Promise.race = function (promises) {
    for (let i = 0; i < promises.length; i++) {
        return new Promise((resolve, reject) => {
            promises[i].then(v => {
                resolve(v)
            }, r => {
                reject(r)
            })
        })
    }
}

代码优化的步骤:

  • 实现异步任务的成功执行
  • promise构造函数优化
  • then方法返回值优化
  • 完善then方法的内部代码
  • 封装common函数,提高代码的可读性
  • 在promise构造函数上挂载一个resolve和reject方法
  • 为promise构造函数挂载catch方法

  • 为promise构造函数挂载all方法

  • 为promise构造函数挂载race方法

  • 异步打印的相关优化

显示全文