JavaScript之Promise的实现

为什么要使用Promise对象

在没有Promise对象之前,我们是如何处理异步任务的呢。

当一个异步的操作需要另一个异步操作的结果作为参数时,我们应该如何实现呢。

        // 第一层
        $.ajax({
            url: '',
            success: (res1) => {
                // 第二层
                $.ajax({
                    url: '',
                    data: res1,
                    success: (res2) => {
                        // 第三层
                        $.ajax({
                            url: '',
                            data: res2,
                            success: (res3) => {
                                console.log(res3);
                            }
                        })
                    }
                })
            }
        })

如果想获取上一个异步操作的结果作为下一个异步操作的参数,只能将一个异步操作嵌套一个异步操作的实现。

ES6的Promise出现后,我们就可以防止这种一层一层的嵌套了

        let promise1 = new Promise(function (resolve, reject) {
            $.ajax({
                url: '',
                success: (res1) => {
                    resolve(res1)
                }
            })
        })
        let promise2 = new Promise(function (resolve, reject) {
            $.ajax({
                url: '',
                success: (res2) => {
                    resolve(res2)
                }
            })
        })

        let promise3 = new Promise(function (resolve, reject) {
            $.ajax({
                url: '',
                success: (res3) => {
                    resolve(res3)
                }
            })
        })
        promise1.then(promise2).then(promise3)

Promise的定义

Promise是一个对象,它可以获取异步操作的信息。Promise提供统一的API,各种异步操作可以用同样的方法处理。

Promise对象有两个特点

1、对象状态不受外界影响
Promise对象有三个状态:

  • pending : 进行中
  • fulfilled:已成功
  • rejected:已失败

只有异步操作返回的结果,才可以决定当前是哪种状态,其他任何操作都无法改变这个状态。

2、状态的变化只有两种可能

  • pending变成fulfilled
  • pending变成rejected

只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。

Promise解决的问题

  • 回调地狱,代码难以维护,常常第一个函数的输出是第二个函数的输入
  • Promise支持多个并发的请求,获取并发请求中的数据

Promise的缺点

  • 无法取消Promise,一旦创建它就会立即执行,中途无法取消
  • 如果不设置回调函数,Promise对象内部会抛出错误,可是不会反应到外部
  • 当处于pending状态时,无法得知目前进展到哪个状态

Promise的基本使用

Promise构造函数接收一个函数作为参数,这个函数的两个参数分别是resolverejectresolvereject是两个函数,是JavaScript引擎提供的,不用自己部署。

resolve函数的作用是,将Promise对象的状态从pending改为fulfilled,在异步函数操作成功的时候调用,并将异步操作的结果作为参数传递出去。

reject函数的作用是将Promise对象的状态从pedding改为rejected,在异步操作失败的时候调用,并将异步操作报错作为参数传递出去。

创建一个Promise对象,该对象默认会返回两个属性PromiseStatePromiseResult
在这里插入图片描述

promise相关API

1、Promise构造函数

new Promise (excutor)
  • excutor函数:执行器(resolve,reject)=>{}
  • resolve函数:内部定义成功时回调
  • reject函数:内部定义失败时回调

说明:excutor函数在promise内部是立即同步执行的

2、Promise.prototype.then方法

Promise.prototype.then = function(onResolved,onRejected){}
  • onResolced函数:成功的回调函数
  • onRejected函数:失败的回调函数

3、Promise.prototype.catch方法

Promise.prototype.catch = function(onRejected) {}
  • onRejected函数:失败的回调函数

4、Promise.resolve方法

Promise.resolve(value) 
  • value: 可以是简单类型的数据或Promise对象
  • 返回值:一个成功/失败的Promise对象
        let p = Promise.resolve('asd')
        console.log(p); //Promise {<fulfilled>: 'asd'}
        let p2 = Promise.resolve(new Promise((resolve,reject)=>{
            // resolve('success')
            reject('error')
        }))
        console.log(p2); //Promise {<rejected>: 'error'}

5、Promise.reject方法

Promise.reject(reason)
  • reason:可以是简单类型的数据或promise对象
  • 返回一个失败的Promise对象

6、Promise.all方法

Promise.all(promises)
  • promises: 包含多个promise对象的数组

说明:返回一个新的promise,当所有的promise对象都成功才成功,只要有一个失败就失败

        let p1 = new Promise((resolve, reject) => {
            resolve('ok')
        })

        let p2 = Promise.resolve('success')
        let p3 = Promise.resolve('成功')

        let p4 = Promise.all([p1, p2, p3])
        console.log(p4);

所有Promise对象都成功的返回结果
在这里插入图片描述
有一个失败的Promise对象就返回该错误的Promise对象

        let p1 = new Promise((resolve, reject) => {
            reject('error')
        })

        let p2 = Promise.resolve('success')
        let p3 = Promise.resolve('成功')

        let p4 = Promise.all([p1, p2, p3])
        console.log(p4);

在这里插入图片描述
7、Promise.race方法

Proimse.race(promises)
  • promises: 包含多个Promise对象

说明:返回一个新的Promise,第一个完成的Promise结果就是最终的结果

Promise的关键问题

1、改变Promise对象的状态方式

  • resolve方法:将pending状态改为fulfilled
  • reject方法:将pending状态改为rejected
  • 抛出异常:通过throw抛出错误,将pending状态改为rejected

默认情况:Promise的状态为pending

        let p = new Promise((resolve,reject)=>{

        })
        console.log(p);

在这里插入图片描述
resolve方法:改变Promise状态

        let p = new Promise((resolve,reject)=>{
            resolve('ok')
        })
        console.log(p);

在这里插入图片描述
reject方法:改变Promise状态

        let p = new Promise((resolve,reject)=>{
            reject('error')
        })
        console.log(p);

在这里插入图片描述

2、可以调用多个成功回调

说明:当Promise对象的状态改变的时候,指定的回调都会执行

        let p = new Promise((resolve,reject)=>{
            resolve('ok')
        })
        // 回调一
        p.then((value)=>{
            console.log('1=>',value);
        })
         // 回调二
         p.then((value)=>{
            console.log('2=>',value);
        })

3、then方法可以链式调用

then方法使用链式调用时,上一个then方法必须要有返回值。

        let p = new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve('ok')
            },1000)
        })

        p.then(value => {
            console.log('1');
            return value
        }).then(value => {
            console.log('2');
            console.log(value);
        })

4、中断then方法链式调用
只有一种方法就是返回值为一个pendind状态的Promise对象

        let p = new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve('ok')
            },1000)
        })

        p.then(value => {
            console.log('1');
            return new Promise(()=>{})
        }).then(value => {
            console.log('2');
            console.log(value);
        })

因为一个pending状态的Promise对象是无法调用then方法的

实现Promise对象

        // 定义
        function Promise(executor) {
            // 保存实例对象的this 值
            let self = this
            // 默认promise状态
            this.promiseState = 'pending'
            // 默认prmoise结果值
            this.promiseResult = undefined
            // 保存回调函数 因为可以执行多个回调所以需要用数组存储
            this.callback = []
            //定义resolve方法
            function resolve(data) {
                // 限制promise状态只能改变一次
                if (self.promiseState !== 'pending') return
                // 修改对象状态
                self.promiseState = 'fulfilled'
                // 设置对象结果
                self.promiseResult = data
                // 执行异步操作时保存起来的成功回调
                self.callback.forEach(item => {
                    item.onResolved(data)
                })
            }
            // 定义reject方法
            function reject(data) {
                // 限制promise状态只能改变一次
                if (self.promiseState !== 'pending') return
                // 修改对象状态
                self.promiseState = 'rejected'
                // 设置对象结果
                self.promiseResult = data
                // 执行异步操作时保存起来的成功回调
                self.callback.forEach(item => {
                    item.onRejected(data)
                })
            }

            // 处理抛出的异常需要用trycatch获取
            try {
                // 同步调用 执行器
                executor(resolve, reject)
            } catch (e) {
                // 调用reject方法
                reject(e)
            }
        }
        // 添加then方法
        Promise.prototype.then = function (onResolved, onRejected) {
            let self = this
            // 判断回调函数的参数 异常穿透
            if (typeof onRejected !== 'function') {
                // 创建一个函数
                onRejected = reason => {
                    throw reason
                }
            }
            // 值传递
            if (typeof onResolved !== 'function') {
                // 创建一个函数
                onResolved = value => value
            }
            // 返回值是一个promise对象
            return new Promise((resolve, reject) => {
                // 判断promise的状态
                if (this.promiseState === 'fulfilled') {
                    try {
                        // 获取函数回调的执行结果
                        let result = onResolved(this.promiseResult)
                        // 判断返回结果是否为promise对象
                        if (result instanceof Promise) {
                            // 如果时 promise对象
                            result.then(v => {
                                resolve(v)
                            }, r => {
                                reject(r)
                            })
                        } else {
                            // 结果对象状态为成功
                            resolve(result)
                        }
                    } catch (e) {
                        reject(e)
                    }
                }
                if (this.promiseState === 'rejected') {

                    try {
                        // 获取函数回调的执行结果
                        let result = onRejected(this.promiseResult)
                        // 判断返回结果是否为promise对象
                        if (result instanceof Promise) {
                            // 如果时 promise对象
                            result.then(v => {
                                resolve(v)
                            }, r => {
                                reject(r)
                            })
                        } else {
                            // 结果对象状态为成功
                            resolve(result)
                        }
                    } catch (e) {
                        reject(e)
                    }
                }
                // 当执行器里面的代码时异步的时候需要将then的回调函数保存起来
                // 当异步操作完成改变状态时在去触发保存起来的回调函数
                if (this.promiseState === 'pending') {
                    this.callback.push({
                        onResolved: function () {
                            try {
                                // 执行成功回调
                                let result = onResolved(self.promiseResult)
                                // 判断返回结果是否为promise对象
                                if (result instanceof Promise) {
                                    // 如果时 promise对象
                                    result.then(v => {
                                        resolve(v)
                                    }, r => {
                                        reject(r)
                                    })
                                } else {
                                    // 结果对象状态为成功
                                    resolve(result)
                                }
                            } catch (e) {
                                reject(e)
                            }
                        },
                        onRejected: function () {
                            try {
                                // 执行成功回调
                                let result = onRejected(self.promiseResult)
                                // 判断返回结果是否为promise对象
                                if (result instanceof Promise) {
                                    // 如果时 promise对象
                                    result.then(v => {
                                        resolve(v)
                                    }, r => {
                                        reject(r)
                                    })
                                } else {
                                    // 结果对象状态为成功
                                    resolve(result)
                                }
                            } catch (e) {
                                reject(e)
                            }
                        },
                    })
                }
            })
        }

        // 添加catch放啊
        Promise.prototype.catch = function (onRejected) {
            return this.then(undefined, onRejected)
        }

        // resolve方法
        Promise.resolve = function (value) {
            return new Promise((resolve, reject) => {
                if (value instanceof Promise) {
                    value.then(v => {
                        resolve(v)
                    }, r => {
                        reject(r)
                    })
                } else {
                    resolve(value)
                }
            })
        }

        // reject方法
        Promise.reject = function (reason) {
            return new Promise((resolve, reject) => {
                reject(reason)
            })
        }

        // all方法
        Promise.all = function (promises) {
            return new Promise((resolve, reject) => {
                let count = 0
                let arr = []
                // 遍历每个promise对象
                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) {
            return new Promise((resolve, reject) => {
                // 遍历每个promise对象
                for (let i = 0; i < promises.length; i++) {
                    promises[i].then(v => {
                        resolve(v)
                    }, r => {
                        reject(r)
                    })
                }
            })
        }


版权声明:本文为weixin_47303886原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。