精华内容
下载资源
问答
  • 原生js手写Promise
  • 手写Promise

    2020-11-02 17:07:44
    手写一个Promise类一、手写Promise实现的功能二、代码部分总结 一、手写Promise实现的功能 1、Promise就是一个类,在执行类的时候,需要传递一个执行器(函数)进去,执行器会立刻执行 2、Promise有三种状态,分别为 ...


    一、实现的功能

    1、Promise就是一个类,在执行类的时候,需要传递一个执行器(函数)进去,执行器会立刻执行

    2、Promise有三种状态,分别为 等待 pending 成功 fulfilled 失败 rejected
    pending => fulfilled || pending => rejected
    状态一旦确定就不能改变

    3、resolve和reject是用来更改状态的
    resolve : fulfilled
    reject : rejected

    4、then方法内部做的事情就是判断状态 如果状态是成功 调用成功的返回函数 如果状态是失败 调用失败的回调函数 then方法是被定义在原型对象中的

    5、then成功回调有一个参数,表示成功之后的值,then失败回调有一个参数,表示失败的原因

    6、同一个promise对象下面的then方法是可以被调用多次的,then方法是可以链式调用的,后面的then方法回调函数拿到的值是上一个then方法的回调函数的返回值

    二、代码部分

    const PENDING = "pending";
    const FULFILLED = "fulfilled";
    const REJECTED = "rejected";
    
    class MyPromise{
        constructor (executor) {
            try { // 尝试调用执行器
                executor(this.resolve,this.reject)
            } catch(e) { // 调用失败
                this.reject(e)
            }
            
        }
        // Promise 状态
        status = PENDING;
        // 成功之后的值
        value = undefined;
        // 失败的原因
        reason = undefined;
        // 成功回调
        successCallback = [];
        // 失败回调
        failCallback = [];
    
        resolve = value => {
            // 如果状态不是等待 阻止程序向下执行
            if(this.status !== PENDING) return
            // 更改状态为成功
            this.status = FULFILLED
            // 保存成功之后的值
            this.value = value
            // 成功回调存在 调用成功回调方法
            // this.successCallback && this.successCallback(this.value)
            // 因为then是可以多次调用的
            // this.successCallback.shift(),截取数组中的第一个元素并返回,会改变原数组
            while(this.successCallback.length) this.successCallback.shift()(this.value)
        }
        reject = reason => {
            if(this.status !== PENDING) return
            // 更改状态为失败
            this.status = REJECTED
            // 保存失败的值
            this.reason = reason
            // 成功回调存在 调用成功回调方法
            // this.failCallback && this.failCallback(this.value)
            while(this.failCallback.length) this.failCallback.shift()(this.value)
        }
        then(successCallback, failCallback){
            // 当没有成功回调时,将value值往下传递
            successCallback = successCallback ? successCallback : value => value;
            // 当没有失败回调时,抛出异常
            failCallback = failCallback ? failCallback : reason => { throw reason };
            // 创建一个新的 Promise对象
            let promise2 = new MyPromise((resolve, reject)=>{
                // 判断状态
                if(this.status === FULFILLED){
                    setTimeout(()=>{
                        try {
                            // 定义 val接收成功回调的返回值
                            let x = successCallback(this.value);
                            // resolve(val)
    
                            // 判断val的值是一个普通值,还是promise对象,
                            // 如果是普通值,直接调用resolve
                            // 如果是promise对象,查看promise对象返回的结果
                            // 再根据promise对象返回的结果,决定调用resolve还是reject
                            resolvePromise(promise2, x, resolve, reject)
                        } catch(e) {
                            reject(e)
                        }
                        
                    },0)
                }else if(this.status === REJECTED){
                    setTimeout(()=>{
                        try {
                            // 定义 val接收成功回调的返回值
                            let x = failCallback(this.reason)
                            // resolve(val)
    
                            // 判断val的值是一个普通值,还是promise对象,
                            // 如果是普通值,直接调用resolve
                            // 如果是promise对象,查看promise对象返回的结果
                            // 再根据promise对象返回的结果,决定调用resolve还是reject
                            resolvePromise(promise2, x, resolve, reject)
                        } catch(e) {
                            reject(e)
                        }
                    },0)
                }else{ 
                    // 当异步改变状态时,此时状态为 pending,将成功或失败回调缓存起来
                    // 每次调用 then方法 ,都会缓存一个回调
                    this.successCallback.push(() => {
                        setTimeout(()=>{
                            try {
                                // 定义 val接收成功回调的返回值
                                let x = successCallback(this.value);
                                // resolve(val)
        
                                // 判断val的值是一个普通值,还是promise对象,
                                // 如果是普通值,直接调用resolve
                                // 如果是promise对象,查看promise对象返回的结果
                                // 再根据promise对象返回的结果,决定调用resolve还是reject
                                resolvePromise(promise2, x, resolve, reject)
                            } catch(e) {
                                reject(e)
                            }
                            
                        },0)
                    })
                    this.failCallback.push(() => {
                        setTimeout(()=>{
                            try {
                                // 定义 val接收成功回调的返回值
                                let x = failCallback(this.reason)
                                // resolve(val)
        
                                // 判断val的值是一个普通值,还是promise对象,
                                // 如果是普通值,直接调用resolve
                                // 如果是promise对象,查看promise对象返回的结果
                                // 再根据promise对象返回的结果,决定调用resolve还是reject
                                resolvePromise(promise2, x, resolve, reject)
                            } catch(e) {
                                reject(e)
                            }
                        },0)
                    })
                }
            })
            // 返回一个 Promise对象
            return promise2;
        }
        catch(failCallback){
            return this.then(undefined, failCallback)
        }
        finally(callback){
            // 无论成功或失败都要执行
            return this.then(value=>{
                return MyPromise.resolve(callback()).then(() => value)
            },reason => {
                return MyPromise.resolve(callback()).then(() => {throw reason})
            })
        }
        static all(array){
            let result = []
            let index = 0 // 由index判断是否执行完所有代码,并将数据添加进result中了
            return new MyPromise((resolve, reject) => {
                // 由addData方法像 result 中添加数据
                function addData(key, val){
                    result[key] = val
                    index ++
                    if(index == array.length){
                        resolve(result)
                    }
                }
                array.forEach((item,index) => {
                    if(item instanceof MyPromise){
                        item.then(val => addData(index,val), reason => reject(reason))
                    }else{
                        addData(index,item)
                    }
                })
            })
        }
        static resolve(val){
            // promise对象直接原样返回
            if(val instanceof MyPromise) return val;
            // 数值类型将其作为一个新的promise对象的返回值返回
            return new MyPromise(resolve => resolve(val))
        }
    }
    function resolvePromise(promise2, x, resolve, reject){
        if(promise2 === x){
            // console.log('传入了同一个promise');
            return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
        }
        if(x instanceof MyPromise){
            // promise对象
            // x.then(value => resolve(value), reason => reject(reason))
            // 优化为:
            x.then(resolve, reject)
        }else{
            // 普通值
            resolve(x)
        }
    }
    
    展开全文
  • 手写 Promise

    2021-05-10 20:27:22
    手写 Promise 实现一个简易版 Promise 在完成符合 Promise/A+ 规范的代码之前,我们可以先来实现一个简易版 Promise,因为在面试中,如果你能实现出一个简易版的 Promise 基本可以过关了。 那么我们先来搭建构建函数...

    手写 Promise

    实现一个简易版 Promise

    在完成符合 Promise/A+ 规范的代码之前,我们可以先来实现一个简易版 Promise,因为在面试中,如果你能实现出一个简易版的 Promise 基本可以过关了。

    那么我们先来搭建构建函数的大体框架

    const PENDING = 'pending'
    const RESOLVED = 'resolved'
    const REJECTED = 'rejected'
    
    function MyPromise(fn) {
      const that = this
      that.state = PENDING
      that.value = null
      that.resolvedCallbacks = []
      that.rejectedCallbacks = []
      // 待完善 resolve 和 reject 函数
      // 待完善执行 fn 函数
    }
    
    • 首先我们创建了三个常量用于表示状态,对于经常使用的一些值都应该通过常量来管理,便于开发及后期维护
    • 在函数体内部首先创建了常量 that,因为代码可能会异步执行,用于获取正确的 this 对象
    • 一开始 Promise 的状态应该是 pending
    • value 变量用于保存 resolve 或者 reject 中传入的值
    • resolvedCallbacksrejectedCallbacks 用于保存 then 中的回调,因为当执行完 Promise 时状态可能还是等待中,这时候应该把 then 中的回调保存起来用于状态改变时使用

    接下来我们来完善 resolvereject 函数,添加在 MyPromise 函数体内部

    function resolve(value) {
      if (that.state === PENDING) {
        that.state = RESOLVED
        that.value = value
        that.resolvedCallbacks.map(cb => cb(that.value))
      }
    }
    
    function reject(value) {
      if (that.state === PENDING) {
        that.state = REJECTED
        that.value = value
        that.rejectedCallbacks.map(cb => cb(that.value))
      }
    }
    

    这两个函数代码类似,就一起解析了

    • 首先两个函数都得判断当前状态是否为等待中,因为规范规定只有等待态才可以改变状态
    • 将当前状态更改为对应状态,并且将传入的值赋值给 value
    • 遍历回调数组并执行

    完成以上两个函数以后,我们就该实现如何执行 Promise 中传入的函数了

    try {
      fn(resolve, reject)
    } catch (e) {
      reject(e)
    }
    
    • 实现很简单,执行传入的参数并且将之前两个函数当做参数传进去
    • 要注意的是,可能执行函数过程中会遇到错误,需要捕获错误并且执行 reject 函数

    最后我们来实现较为复杂的 then 函数

    MyPromise.prototype.then = function(onFulfilled, onRejected) {
      const that = this
      onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
      onRejected =
        typeof onRejected === 'function'
          ? onRejected
          : r => {
              throw r
            }
      if (that.state === PENDING) {
        that.resolvedCallbacks.push(onFulfilled)
        that.rejectedCallbacks.push(onRejected)
      }
      if (that.state === RESOLVED) {
        onFulfilled(that.value)
      }
      if (that.state === REJECTED) {
        onRejected(that.value)
      }
    }
    
    • 首先判断两个参数是否为函数类型,因为这两个参数是可选参数

    • 当参数不是函数类型时,需要创建一个函数赋值给对应的参数,同时也实现了透传,比如如下代码

      // 该代码目前在简单版中会报错
      // 只是作为一个透传的例子
      Promise.resolve(4).then().then((value) => console.log(value))
      
    • 接下来就是一系列判断状态的逻辑,当状态不是等待态时,就去执行相对应的函数。如果状态是等待态的话,就往回调函数中 push 函数,比如如下代码就会进入等待态的逻辑

      new MyPromise((resolve, reject) => {
        setTimeout(() => {
          resolve(1)
        }, 0)
      }).then(value => {
        console.log(value)
      })
      

    以上就是简单版 Promise 实现,接下来一小节是实现完整版 Promise 的解析,相信看完完整版的你,一定会对于 Promise 的理解更上一层楼。

    实现一个符合 Promise/A+ 规范的 Promise

    这小节代码需要大家配合规范阅读,因为大部分代码都是根据规范去实现的。

    我们先来改造一下 resolvereject 函数

    function resolve(value) {
      if (value instanceof MyPromise) {
        return value.then(resolve, reject)
      }
      setTimeout(() => {
        if (that.state === PENDING) {
          that.state = RESOLVED
          that.value = value
          that.resolvedCallbacks.map(cb => cb(that.value))
        }
      }, 0)
    }
    function reject(value) {
      setTimeout(() => {
        if (that.state === PENDING) {
          that.state = REJECTED
          that.value = value
          that.rejectedCallbacks.map(cb => cb(that.value))
        }
      }, 0)
    }
    
    • 对于 resolve 函数来说,首先需要判断传入的值是否为 Promise 类型
    • 为了保证函数执行顺序,需要将两个函数体代码使用 setTimeout 包裹起来

    接下来继续改造 then 函数中的代码,首先我们需要新增一个变量 promise2,因为每个 then 函数都需要返回一个新的 Promise 对象,该变量用于保存新的返回对象,然后我们先来改造判断等待态的逻辑

    if (that.state === PENDING) {
      return (promise2 = new MyPromise((resolve, reject) => {
        that.resolvedCallbacks.push(() => {
          try {
            const x = onFulfilled(that.value)
            resolutionProcedure(promise2, x, resolve, reject)
          } catch (r) {
            reject(r)
          }
        })
    
        that.rejectedCallbacks.push(() => {
          try {
            const x = onRejected(that.value)
            resolutionProcedure(promise2, x, resolve, reject)
          } catch (r) {
            reject(r)
          }
        })
      }))
    }
    
    • 首先我们返回了一个新的 Promise 对象,并在 Promise 中传入了一个函数
    • 函数的基本逻辑还是和之前一样,往回调数组中 push 函数
    • 同样,在执行函数的过程中可能会遇到错误,所以使用了 try...catch 包裹
    • 规范规定,执行 onFulfilled 或者 onRejected 函数时会返回一个 x,并且执行 Promise 解决过程,这是为了不同的 Promise 都可以兼容使用,比如 JQuery 的 Promise 能兼容 ES6 的 Promise

    接下来我们改造判断执行态的逻辑

    if (that.state === RESOLVED) {
      return (promise2 = new MyPromise((resolve, reject) => {
        setTimeout(() => {
          try {
            const x = onFulfilled(that.value)
            resolutionProcedure(promise2, x, resolve, reject)
          } catch (reason) {
            reject(reason)
          }
        })
      }))
    }
    
    • 其实大家可以发现这段代码和判断等待态的逻辑基本一致,无非是传入的函数的函数体需要异步执行,这也是规范规定的
    • 对于判断拒绝态的逻辑这里就不一一赘述了,留给大家自己完成这个作业

    最后,当然也是最难的一部分,也就是实现兼容多种 PromiseresolutionProcedure 函数

    function resolutionProcedure(promise2, x, resolve, reject) {
      if (promise2 === x) {
        return reject(new TypeError('Error'))
      }
    }
    

    首先规范规定了 x 不能与 promise2 相等,这样会发生循环引用的问题,比如如下代码

    let p = new MyPromise((resolve, reject) => {
      resolve(1)
    })
    let p1 = p.then(value => {
      return p1
    })
    

    然后需要判断 x 的类型

    if (x instanceof MyPromise) {
        x.then(function(value) {
            resolutionProcedure(promise2, value, resolve, reject)
        }, reject)
    }
    

    这里的代码是完全按照规范实现的。如果 xPromise 的话,需要判断以下几个情况:

    1. 如果 x 处于等待态,Promise 需保持为等待态直至 x 被执行或拒绝
    2. 如果 x 处于其他状态,则用相同的值处理 Promise

    当然以上这些是规范需要我们判断的情况,实际上我们不判断状态也是可行的。

    接下来我们继续按照规范来实现剩余的代码

    let called = false
    if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
      try {
        let then = x.then
        if (typeof then === 'function') {
          then.call(
            x,
            y => {
              if (called) return
              called = true
              resolutionProcedure(promise2, y, resolve, reject)
            },
            e => {
              if (called) return
              called = true
              reject(e)
            }
          )
        } else {
          resolve(x)
        }
      } catch (e) {
        if (called) return
        called = true
        reject(e)
      }
    } else {
      resolve(x)
    }
    
    • 首先创建一个变量 called 用于判断是否已经调用过函数
    • 然后判断 x 是否为对象或者函数,如果都不是的话,将 x 传入 resolve
    • 如果 x 是对象或者函数的话,先把 x.then 赋值给 then,然后判断 then 的类型,如果不是函数类型的话,就将 x 传入 resolve
    • 如果 then 是函数类型的话,就将 x 作为函数的作用域 this 调用之,并且传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise,两个回调函数都需要判断是否已经执行过函数,然后进行相应的逻辑
    • 以上代码在执行的过程中如果抛错了,将错误传入 reject 函数中

    以上就是符合 Promise/A+ 规范的实现了,如果你对于这部分代码尚有疑问,欢迎在评论中与我互动。

    then,然后判断 then 的类型,如果不是函数类型的话,就将 x 传入 resolve

    • 如果 then 是函数类型的话,就将 x 作为函数的作用域 this 调用之,并且传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise,两个回调函数都需要判断是否已经执行过函数,然后进行相应的逻辑
    • 以上代码在执行的过程中如果抛错了,将错误传入 reject 函数中

    以上就是符合 Promise/A+ 规范的实现了,如果你对于这部分代码尚有疑问,欢迎在评论中与我互动。

    展开全文
  • 手写promise

    2020-11-12 21:44:27
    手写promise 1.resolve/reject函数 改变promise对象的状态 并且只能改变一次,同步调用executor (function(w) { /* 1.resolve/reject函数 改变promise对象的状态 并且只能改变一次,同步调用executor */ ...

    手写promise

    1.resolve/reject函数 改变promise对象的状态 并且只能改变一次,同步调用executor

    (function(w) {
        /* 
            1.resolve/reject函数 改变promise对象的状态 并且只能改变一次,同步调用executor
        */
        function MyPromise(executor) {
            const that = this;
    		//设置promise对象状态
            that._status = "pending"
           
            function resolve() {
                if(that._status !== "pending") return;
                that._status = "resolved"  
            }
    
            function reject() {
                if(that._status !== "pending") return;
                that._status = "rejected" 
            }
    		//同步调用executor
            executor(resolve, reject)
        }
        w.MyPromise = MyPromise;
    })(window);
    

    2.调用resolve/reject函数时,触发then方法,调用其回电函数。同时resolve/reject进行传值

    (function(w) {
        /* 
            1.resolve/reject函数 改变promise对象的状态 并且只能改变一次,同步调用executor
            2.调用resolve/reject函数时,触发then方法,调用其回电函数。同时resolve/reject进行传值
        */
        function MyPromise(executor) {
            const that = this;
    
            that._status = "pending"
            that._result = undefined;//初始化结果值
            that._cb = {}
    
            function resolve(value) {
                if (that._status !== "pending") return;
                that._status = "resolved"
                that._result = value
                //resolve同步执行,但是onResolved是异步调用的,所以加个计时器实现异步调用
                setTimeout(() => {
                    that._cb.onResolved && that._cb.onResolved(value)
                    //that._callbacks.onResolved?.(value);// 新的运算符 ?. 可选链
                }, 0)
            }
    
            function reject(reason) {
                if (that._status !== "pending") return;
                that._status = "rejected"
                that._result = reason
                setTimeout(() => {
                    that._cb.onRejected && that._cb.onRejected(reason)
                }, 0)
            }
    
            executor(resolve, reject)
        }
    
        MyPromise.prototype.then = function (onResolved, onRejected) {
            this._cb.onResolved = onResolved;
            this._cb.onRejected = onRejected;
        }
    
        w.MyPromise = MyPromise;
    })(window);
    

    3.解决then方法中的返回值问题,同时接受值的传递

    (function(w) {
        /* 
            1.resolve/reject函数 改变promise对象的状态 并且只能改变一次,同步调用executor
            2.调用resolve/reject函数时,触发then方法,调用其回电函数。同时resolve/reject进行传值
            3.解决then方法中的返回值问题,同时接受值的传递
        */
        function MyPromise(executor) {
            const that = this;
    
            that._status = "pending"
            that._result = undefined;//初始化结果值
            that._cb = {}
    
            function resolve(value) {
                if (that._status !== "pending") return;
                that._status = "resolved"
                that._result = value
                //resolve同步执行,但是onResolved是异步调用的,所以加个计时器实现异步调用
                setTimeout(() => {
                    that._cb.onResolved && that._cb.onResolved(value)
                    //that._callbacks.onResolved?.(value);// 新的运算符 ?. 可选链
                }, 0)
            }
    
            function reject(reason) {
                if (that._status !== "pending") return;
                that._status = "rejected"
                that._result = reason
                setTimeout(() => {
                    that._cb.onRejected && that._cb.onRejected(reason)
                }, 0)
            }
    
            executor(resolve, reject)
        }
    
        MyPromise.prototype.then = function (onResolved, onRejected) { 
            // 状态怎么改变?
          // 什么场景要调用resolve,什么场景要调用reject
          /*
            then返回值是一个新的promise1对象,
                他的状态看里面函数调用的返回值:
                  1.如果返回值是一个promise2对象,那么这个promise2的状态是什么,promise1的状态就是什么
                  2.如果返回值不是promise对象,或者没有返回值,那么promise1对象默认是成功状态,并返回return的值
                  3.如果函数调用报错了,那么promise1对象就会是失败状态
          */
    		 const that = this this指向实例对象promise
            //返回一个新的promise对象,实现链式调用 ,同时要得到onResolved的返回值,来判断其是不是promise对象,来决定then的返回值
            return new MyPromise((resolve, reject) => {
                
                that._cb.onResolved = function(value) {
                    try{
                        const result = onResolved(value); //得到返回值
                        if(result instanceof MyPromise) {
                            result.then(resolve, reject) //状态1
                        }else{
                            resolve(result) //状态2
                        }
                    }catch(err){
                        reject(err) //状态3
                    }
                }
    
                that._cb.onRejected = function(reason) {
                    try{
                        const result = onRejected(reason); //得到返回值
                        if(result instanceof MyPromise) {
                            result.then(resolve, reject) //状态1
                        }else{
                            resolve(result) //状态2
                        }
                    }catch(err){
                        reject(err) //状态3
                    }
                }
            })
        }
    
        w.MyPromise = MyPromise;
    })(window);
    

    4.实现catch方法

    (function(w) {
        /* 
            1.resolve/reject函数 改变promise对象的状态 并且只能改变一次,同步调用executor
            2.调用resolve/reject函数时,触发then方法,调用其回电函数。同时resolve/reject进行传值
            3.解决then方法中的返回值问题,同时接受值的传递
            4.实现catch方法
        */
        function MyPromise(executor) {
            const that = this;
    
            that._status = "pending"
            that._result = undefined;//初始化结果值
            that._cb = {}
    
            function resolve(value) {
                if (that._status !== "pending") return;
                that._status = "resolved"
                that._result = value
                //resolve同步执行,但是onResolved是异步调用的,所以加个计时器实现异步调用
                setTimeout(() => {
                    that._cb.onResolved && that._cb.onResolved(value)
                    //that._callbacks.onResolved?.(value);// 新的运算符 ?. 可选链
                }, 0)
            }
    
            function reject(reason) {
                if (that._status !== "pending") return;
                that._status = "rejected"
                that._result = reason
                setTimeout(() => {
                    that._cb.onRejected && that._cb.onRejected(reason)
                }, 0)
            }
    
            executor(resolve, reject)
        }
    
        MyPromise.prototype.then = function (onResolved, onRejected) {
            // 状态怎么改变?
          // 什么场景要调用resolve,什么场景要调用reject
          /*
            then返回值是一个新的promise1对象,
                他的状态看里面函数调用的返回值:
                  1.如果返回值是一个promise2对象,那么这个promise2的状态是什么,promise1的状态就是什么
                  2.如果返回值不是promise对象,或者没有返回值,那么promise1对象默认是成功状态,并返回return的值
                  3.如果函数调用报错了,那么promise1对象就会是失败状态
          */
         const that = this this指向实例对象promise
          //为了解决then方法,不传第二个函数 (失败回调)
          onRejected = typeof onRejected === "function" ? onRejected : (reason) => {throw reason}  
          //为了catch方法,不传第一个回调
          onResolved = typeof onResolved === "function" ? onResolved : (value) => value
            //返回一个新的promise对象,实现链式调用 ,同时要得到onResolved的返回值,来判断其是不是promise对象,来决定then的返回值
            return new MyPromise((resolve, reject) => {
                
                that._cb.onResolved = function(value) {
                    try{
                        const result = onResolved(value); //得到返回值
                        if(result instanceof MyPromise) {
                            result.then(resolve, reject) //状态1
                        }else{
                            resolve(result) //状态2
                        }
                    }catch(err){
                        reject(err) //状态3
                    }
                }
    
                that._cb.onRejected = function(reason) {
                    try{
                        const result = onRejected(reason); //得到返回值
                        if(result instanceof MyPromise) {
                            result.then(resolve, reject) //状态1
                        }else{
                            resolve(result) //状态2
                        }
                    }catch(err){
                        reject(err) //状态3
                    }
                }
            })
        }
    
        MyPromise.prototype.catch = function(onRejected) {
            return this.then(undefined, onRejected)
        }
    
        w.MyPromise = MyPromise;
    })(window);
    
    展开全文
  • 手写 promise

    2020-11-04 12:32:12
    一、 Promise 的理解 Promise 是 JS 中进行异步编程的新解决方案 promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值 promise 有 3 种状态,pending、resolved、rejected promise 的状态改变(只有 2 ...

    一、 Promise 的理解

    • Promise 是 JS 中进行异步编程的新解决方案
    • promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值
    • promise 有 3 种状态,pending、resolved、rejected
    • promise 的状态改变(只有 2 种, 只能改变一次),pending 变为 resolved, pending 变为 rejected

    二、Promise 构造函数

    /* 
      Promise构造函数
      */
    const PENDING = 'pending' // 初始未确定的状态
    const RESOLVED = 'resolved' // 成功的状态
    const REJECTED = 'rejected' // 失败的状态
    function Promise(excutor) {
      const self = this // Promise的实例对象
      self.status = PENDING // 状态属性, 初始值为pending, 代表初始未确定的状态
      self.data = undefined // 用来存储结果数据的属性, 初始值为undefined
      self.callbacks = [] // {onResolved(){}, onRejected(){}}
    
      /* 
        将promise的状态改为成功, 指定成功的value
        */
      function resolve(value) {
        // 如果当前不是pending, 直接结束
        if (self.status !== PENDING) return
    
        self.status = RESOLVED // 将状态改为成功
        self.data = value // 保存成功的value
    
        // 异步调用所有缓存的待执行成功的回调函数
        if (self.callbacks.length > 0) {
          // 启动一个延迟时间为0的定时器, 在定时器的回调中执行所有成功的回调
          setTimeout(() => {
            self.callbacks.forEach((cbsObj) => {
              cbsObj.onResolved(value)
            })
          })
        }
      }
    
      /* 
        将promise的状态改为失败, 指定失败的reason
        */
      function reject(reason) {
        // 如果当前不是pending, 直接结束
        if (self.status !== PENDING) return
    
        self.status = REJECTED // 将状态改为失败
        self.data = reason // 保存reason数据
    
        // 异步调用所有缓存的待执行失败的回调函数
        if (self.callbacks.length > 0) {
          // 启动一个延迟时间为0的定时器, 在定时器的回调中执行所有失败的回调
          setTimeout(() => {
            self.callbacks.forEach((cbsObj) => {
              cbsObj.onRejected(reason)
            })
          })
        }
      }
    
      // 调用excutor来启动异步任务
      try {
        excutor(resolve, reject)
      } catch (error) {
        // 执行器执行出错, 当前promise变为失败
        reject(error)
      }
    }
    

    三、Promise.prototype.then 方法

    /* 
      用来指定成功/失败回调函数的方法
          1). 如果当前promise是resolved, 异步执行成功的回调函数onResolved
          2). 如果当前promise是rejected, 异步执行成功的回调函数onRejected
          3). 如果当前promise是pending, 保存回调函数
      返回一个新的promise对象
          它的结果状态由onResolved或者onRejected执行的结果决定
          2.1). 抛出error ==> 变为rejected, 结果值为error
          2.2). 返回值不是promise   ==> 变为resolved, 结果值为返回值
          2.3). 返回值是promise    ===> 由这个promise的决定新的promise的结果(成功/失败)
      */
    Promise.prototype.then = function (onResolved, onRejected) {
      const self = this
    
      onResolved = typeof onResolved === 'function' ? onResolved : (value) => value // 将value向下传递
      onRejected =
        typeof onRejected === 'function'
          ? onRejected
          : (reason) => {
              throw reason
            } // 将reason向下传递
    
      return new Promise((resolve, reject) => {
        // 什么时候改变它的状态
        /* 
          1. 调用指定的回调函数
          2. 根据回调执行结果来更新返回promise的状态
        */
        function handle(callback) {
          try {
            const result = callback(self.data)
            if (!(result instanceof Promise)) {
              //  2.2). 返回值不是promise   ==> 变为resolved, 结果值为返回值
              resolve(result)
            } else {
              // 2.3). 返回值是promise    ===> 由这个promise的决定新的promise的结果(成功/失败)
              result.then(
                (value) => resolve(value),
                (reason) => reject(reason)
              )
            }
          } catch (error) {
            // 2.1). 抛出error ==> 变为rejected, 结果值为error
            reject(error)
          }
        }
    
        if (self.status === RESOLVED) {
          setTimeout(() => {
            handle(onResolved)
          })
        } else if (self.status === REJECTED) {
          setTimeout(() => {
            handle(onRejected)
          })
        } else {
          // PENDING
          self.callbacks.push({
            onResolved(value) {
              handle(onResolved)
            },
            onRejected(reason) {
              handle(onRejected)
            },
          })
        }
      })
    }
    

    四、Promise.prototype.catch 方法

    /* 
     用来指定失败回调函数的方法
     可以使用then方法来简化catch方法
    */
    Promise.prototype.catch = function (onRejected) {
      return this.then(undefined, onRejected)
    }
    

    五、Promise.resolve 方法

    /* 
      用来返回一个指定vlaue的成功的promise
      value可能是一个一般的值, 也可能是promise对象
      */
    Promise.resolve = function (value) {
      return new Promise((resolve, reject) => {
        // 如果value是一个promise, 最终返回的promise的结果由value决定
        if (value instanceof Promise) {
          value.then(resolve, reject)
        } else {
          // value不是promise, 返回的是成功的promise, 成功的值就是value
          resolve(value)
        }
      })
    }
    

    六、Promise.reject 方法

    /* 
      用来返回一个指定reason的失败的promise
      */
    Promise.reject = function (reason) {
      return new Promise((resolve, reject) => {
        reject(reason)
      })
    }
    

    七、Promise.all 方法

    /* 
      返回一个promise, 只有当数组中所有promise都成功才成功, 否则失败
      */
    Promise.all = function (promises) {
      return new Promise((resolve, reject) => {
        let resolvedCount = 0 // 已经成功的数量
        const values = new Array(promises.length) // 用来保存成功promise的value值
        // 遍历所有promise, 取其对应的结果
        promises.forEach((p, index) => {
          p.then(
            (value) => {
              resolvedCount++
              values[index] = value
              if (resolvedCount === promises.length) {
                // 都成功了,调用resolve把所有的结果带过去
                resolve(values)
              }
            },
            (reason) => reject(reason) // 失败了直接,调用reject
          )
        })
      })
    }
    

    八、 Promise.race 方法

    /* 
      返回一个promise, 由第一个完成promise决定
      */
    Promise.race = function (promises) {
      return new Promise((resolve, reject) => {
        // 遍历所有promise, 取其对应的结果
        promises.forEach((p) => {
          // 返回的promise由第一个完成p来决定其结果
          p.then(resolve, reject)
        })
      })
    }
    
    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,310
精华内容 3,324
关键字:

手写promise