Promise对象 异步编程

Promise 的含义

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise对象有以下两个特点。

(1)对象的状态不受外界影响Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

Promise也有一些缺点:

  1. 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
  2. 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
  3. 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

为什么要用promise

1. 指定回调函数的方式更加灵活: 
    旧的: 必须在启动异步任务前指定
    promise: 启动异步任务 => 返回promie对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定)

const p = new Promise((resolve, reject) => {
    console.log('执行 executor同步函数')
    let time = Date.now();
    setTimeout(() => {
        if (time % 2 === 0) {
            resolve(time)
        } else {
            reject(time)
        }
    }, 1000)

})

setTimeout(() => {
    p.then(value => {
        console.log('value', value)
    }, reason => {
        console.log('reason', reason)
    })
}, 3000)

 2. 支持链式调用, 可以解决回调地狱问题
    什么是回调地狱: 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调函数执行的条件
    回调地狱的缺点: 不便于阅读 / 不便于异常处理
    解决方案:promise链式调用
    终极解决方案:async/await

Promise API
1. Promise构造函数: Promise (excutor) {}
excutor 执行器函数: 同步执行  (resolve, reject) => {}
resolve函数: 内部定义成功时我们调用的函数 value => {}
reject函数: 内部定义失败时我们调用的函数 reason => {}
说明: excutor会在Promise内部立即同步回调,异步操作在执行器中执行
定义:new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;

2. Promise.prototype.then方法: (onResolved, onRejected) => {}
onResolved函数: 成功的回调函数  (value) => {}
onRejected函数: 失败的回调函数 (reason) => {}
说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调
返回一个新的promise对象
then接口定义:then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;

3. Promise.prototype.catch方法: (onRejected) => {}
onRejected函数: 失败的回调函数 (reason) => {}
说明: then()的语法糖, 相当于: then(undefined, onRejected)
catch接口定义:catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;

4. Promise.resolve方法: (value) => {}
value: 成功的数据或promise对象
说明: 返回一个成功/失败的promise对象  resolve<T>(value: T | PromiseLike<T>): Promise<T>;

5. Promise.reject方法: (reason) => {}
reason: 失败的原因
说明: 返回一个失败的promise对象 reject<T = never>(reason?: any): Promise<T>;

6. Promise.all方法: (promises) => {}
promises: 包含n个promise的数组
说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败
all<T>(values: readonly (T | PromiseLike<T>)[]): Promise<T[]>;

7. Promise.race方法: (promises) => {}
promises: 包含n个promise的数组
说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态
 race<T>(values: readonly T[]): Promise<T extends PromiseLike<infer U> ? U : T>;

 

使用的常见问题
  1.  如何改变promise的状态?
    1. resolve(value): 如果当前是pending就会变为resolved
    2.  reject(reason): 如果当前是pending就会变为rejected
    3. 抛出异常: 如果当前是pending就会变为rejected
  2.  一个promise指定多个成功/失败回调函数, 都会调用吗?
    1.  当promise改变为对应状态时都会调用
  3. 改变promise状态和指定回调函数谁先谁后?
    (1)都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
    (2)如何先改状态再指定回调?
        ①在执行器中直接调用resolve()/reject()
        ②延迟更长时间才调用then()
    (3)什么时候才能得到数据?
        ①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
        ②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
  4. promise.then()返回的新promise的结果状态由什么决定?
      (1)简单表达: 由then()指定的回调函数执行的结果决定
      (2)详细表达:
          ①如果抛出异常, 新promise变为rejected, reason为抛出的异常
          ②如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值
          ③如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
  5. promise如何串连多个操作任务?
       (1)promise的then()返回一个新的promise, 可以开成then()的链式调用
      (2)通过then的链式调用串连多个同步/异步任务
  6. promise异常传透?
     (1)当使用promise的then链式调用时, 可以在最后指定失败的回调,
     (2)前面任何操作出了异常, 都会传到最后失败的回调中处理
  7.  
    中断promise链?
    (1)当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数
    (2)办法: 在回调函数中返回一个pending状态的promise对象      return new Promise(()=>{})
 
自定义Promise
// 自定义Promise
// ES5匿名函数自调用实现模块化
(function (window) {
    const PENDING = 'pending'
    const RESOLVED = 'resolved'
    const REJECTED = 'rejected'

    // 参数为executor函数
    function Promise(executor) {
        const that = this
        // 三个属性
        that.status = PENDING //Promise对象状态属性,初始状态为 pending
        that.data = 'undefined' // 用于存储结果数据
        that.callbacks = [] //保存待执行的回调函数 ,数据结构:{onResolved(){},onRejected(){}}

        function resolve(value) {
            // RESOLVED 状态只能改变一次
            if (that.status !== PENDING) {
                return
            }
            that.status = RESOLVED
            that.data = value
            //执行异步回调函数 onResolved
            if (that.callbacks.length > 0) {
                setTimeout(() => { // 放入队列中执行所有成功的回调
                    that.callbacks.forEach(callbackObj => {
                        callbackObj.onResolved(value)
                    })
                })
            }
        }

        function reject(seaon) {
            if (that.status !== PENDING) {
                return
            }
            that.status = REJECTED
            that.data = seaon
            //执行异步回调函数 onRejected
            if (that.callbacks.length > 0) {
                setTimeout(() => { // 放入队列中执行所有失败的回调
                    that.callbacks.forEach(callbackObj => {
                        callbackObj.onRejected(seaon)
                    })
                })
            }
        }

        try { //执行器函数立即执行
            executor(resolve, reject)
        } catch (e) {
            reject(e)
        }
    }

    //Promise原型对象 then ,两个回掉函数 成功 onResolved ,失败onRejected
    //返回一个新的Promise对象
    Promise.prototype.then = function (onResolved, onRejected) {
        onResolved = typeof onResolved === 'function' ? onResolved : value => value // 向后传递成功的value
        // 指定默认的失败的回调(实现错误/异常传透的关键点)
        onRejected = typeof onRejected === 'function' ? onRejected : reason => {
            throw reason
        } // 抽后传递失败的reason
        const that = this
        return new Promise((resolve, reject) => {

            //调用指定回调函数处理, 根据执行结果, 改变return的promise的状态
            function handle(callback) {
                // 调用成功的回调函数 onResolved
                //1.如果抛出异常,return的promise就 会失败,reason就 是error
                //2.如果回调函数返回不是promise, return的promise就 会成功,value就是返回的值
                //3.如果回调函数返回是promise, return的promise结 果就是这个promise的结果
                try {
                    const result = callback(that.data);
                    if (result instanceof Promise) {
                        result.then(value => resolve(value), reason => reject(reason))
                    } else {
                        resolve(result)
                    }
                } catch (e) {
                    reject(e)
                }
            }

            // 当前状态还是pending状态, 将回调函数保存起来
            if (that.status === PENDING) {
                that.callbacks.push({
                    onResolved(value) {
                        handle(onResolved)
                    },
                    onRejected(reason) {
                        handle(onRejected)
                    }
                })
            } else if (that.status === RESOLVED) {
                setTimeout(() => {
                    handle(onResolved)
                })
            } else {
                setTimeout(() => {
                    //调用失败的回调函数 onRejected
                    handle(onRejected)
                })
            }
        })
    }

    //Promise原型对象 catch ,参数为失败的回掉函数 onRejected
    //返回一个新的Promise对象
    Promise.prototype.catch = function (onRejected) {
        return this.then(undefined, onRejected)
    }

    // Promise函数对象的 resolve 方法
    //返回一个新的Promise对象,Promise.resolve()中可以传入Promise
    Promise.resolve = function (value) {
        return new Promise((resolve, reject) => {
            if (value instanceof Promise) {
                value.then(resolve, reject)
            } else {
                resolve(value)
            }
        })
    }

    // Promise函数对象的 reject 方法
    //返回一个新的Promise对象 Promise.reject中不能再传入Promise
    Promise.reject = function (reason) {
        return new Promise((resolve, reject) => {
            reject(reason)
        })
    }

    // Promise函数对象的 all 方法,接受一个promise类型的数组
    // 返回一个新的Promise对象
    Promise.all = function (promises) {
        // 保证返回的值得结果的顺序和传进来的时候一致
        // 只有全部都成功长才返回成功
        const values = new Array(promises.length) // 指定数组的初始长度
        let successCount = 0
        return new Promise((resolve, reject) => {
            promises.forEach((p, index) => { // 由于p有可能不是一个Promise
                Promise.resolve(p).then(
                    value => {
                        successCount++
                        values[index] = value
                        if (successCount === promises.length) {
                            resolve(values)
                        }
                    },
                    // 如果失败
                    reason => {
                        reject(reason)
                    })
            })
        })

    }
    // Promise函数对象的 race 方法,接受一个promise类型的数组
    // 返回一个新的Promise对象
    Promise.race = function (promises) {
        return new Promise((resolve, reject) => {
            promises.forEach(p => {
                Promise.resolve(p).then(
                    value => {
                        resolve(value)
                    }, reason => {
                        reject(reason)
                    })
            })
        })

    }

    // 把Promise暴露出去
    window.Promise = Promise
})(window)

使用Class定义

// 自定义Promise
// ES5匿名函数自调用实现模块化
(function (window) {
    const PENDING = 'pending'
    const RESOLVED = 'resolved'
    const REJECTED = 'rejected'

    class Promise {
        // 参数为executor函数
        constructor(executor) {
            const that = this
            // 三个属性
            that.status = PENDING //Promise对象状态属性,初始状态为 pending
            that.data = 'undefined' // 用于存储结果数据
            that.callbacks = [] //保存待执行的回调函数 ,数据结构:{onResolved(){},onRejected(){}}

            function resolve(value) {
                // RESOLVED 状态只能改变一次
                if (that.status !== PENDING) {
                    return
                }
                that.status = RESOLVED
                that.data = value
                //执行异步回调函数 onResolved
                if (that.callbacks.length > 0) {
                    setTimeout(() => { // 放入队列中执行所有成功的回调
                        that.callbacks.forEach(callbackObj => {
                            callbackObj.onResolved(value)
                        })
                    })
                }
            }

            function reject(seaon) {
                if (that.status !== PENDING) {
                    return
                }
                that.status = REJECTED
                that.data = seaon
                //执行异步回调函数 onRejected
                if (that.callbacks.length > 0) {
                    setTimeout(() => { // 放入队列中执行所有失败的回调
                        that.callbacks.forEach(callbackObj => {
                            callbackObj.onRejected(seaon)
                        })
                    })
                }
            }

            try { //执行器函数立即执行
                executor(resolve, reject)
            } catch (e) {
                reject(e)
            }
        }

        //Promise原型对象 then ,两个回掉函数 成功 onResolved ,失败onRejected
        //返回一个新的Promise对象
        then(onResolved, onRejected) {
            onResolved = typeof onResolved === 'function' ? onResolved : value => value // 向后传递成功的value
            // 指定默认的失败的回调(实现错误/异常传透的关键点)
            onRejected = typeof onRejected === 'function' ? onRejected : reason => {
                throw reason
            } // 抽后传递失败的reason
            const that = this
            return new Promise((resolve, reject) => {

                //调用指定回调函数处理, 根据执行结果, 改变return的promise的状态
                function handle(callback) {
                    // 调用成功的回调函数 onResolved
                    //1.如果抛出异常,return的promise就 会失败,reason就 是error
                    //2.如果回调函数返回不是promise, return的promise就 会成功,value就是返回的值
                    //3.如果回调函数返回是promise, return的promise结 果就是这个promise的结果
                    try {
                        const result = callback(that.data);
                        if (result instanceof Promise) {
                            result.then(value => resolve(value), reason => reject(reason))
                        } else {
                            resolve(result)
                        }
                    } catch (e) {
                        reject(e)
                    }
                }

                // 当前状态还是pending状态, 将回调函数保存起来
                if (that.status === PENDING) {
                    that.callbacks.push({
                        onResolved(value) {
                            handle(onResolved)
                        },
                        onRejected(reason) {
                            handle(onRejected)
                        }
                    })
                } else if (that.status === RESOLVED) {
                    setTimeout(() => {
                        handle(onResolved)
                    })
                } else {
                    setTimeout(() => {
                        //调用失败的回调函数 onRejected
                        handle(onRejected)
                    })
                }
            })
        }

        //Promise原型对象 catch ,参数为失败的回掉函数 onRejected
        //返回一个新的Promise对象
        catch(onRejected) {
            return this.then(undefined, onRejected)
        }

        // Promise函数对象的 resolve 方法
        //返回一个新的Promise对象,Promise.resolve()中可以传入Promise
        static  resolve = function (value) {
            return new Promise((resolve, reject) => {
                if (value instanceof Promise) {
                    value.then(resolve, reject)
                } else {
                    resolve(value)
                }
            })
        }

        // Promise函数对象的 reject 方法
        //返回一个新的Promise对象 Promise.reject中不能再传入Promise


        static  reject = function (reason) {
            return new Promise((resolve, reject) => {
                reject(reason)
            })
        }

        // Promise函数对象的 all 方法,接受一个promise类型的数组
        // 返回一个新的Promise对象
        static all = function (promises) {
            // 保证返回的值得结果的顺序和传进来的时候一致
            // 只有全部都成功长才返回成功
            const values = new Array(promises.length) // 指定数组的初始长度
            let successCount = 0
            return new Promise((resolve, reject) => {
                promises.forEach((p, index) => { // 由于p有可能不是一个Promise
                    Promise.resolve(p).then(
                        value => {
                            successCount++
                            values[index] = value
                            if (successCount === promises.length) {
                                resolve(values)
                            }
                        },
                        // 如果失败
                        reason => {
                            reject(reason)
                        })
                })
            })

        }

        // Promise函数对象的 race 方法,接受一个promise类型的数组
        // 返回一个新的Promise对象
        static race = function (promises) {
            return new Promise((resolve, reject) => {
                promises.forEach(p => {
                    Promise.resolve(p).then(
                        value => {
                            resolve(value)
                        }, reason => {
                            reject(reason)
                        })
                })
            })

        }
    }

    // 把Promise暴露出去
    window.Promise = Promise
})(window)

来自:https://www.bilibili.com/video/BV1MJ41197Eu?from=search&seid=1177747046204864464

posted @ 2020-07-19 23:34  浪波激泥  阅读(431)  评论(0编辑  收藏  举报