再谈 Promise - 去实现它!

再谈 Promise - 去实现它!

Promise 必须为以下三种状态之一:等待态 Pending、执行态 Fulfilled 和拒绝态 Rejected 。一旦Promise 被 resolve 或 reject,不能再迁移至其他任何状态,即状态 immutable 。

基本过程:

  1. 初始化 Promise 状态(pending
  2. 立即执行 Promise 中传入的 fn 函数,将 Promise 内部 resolvereject 函数作为参数传递给 fn ,按事件机制时机处理
  3. 执行 then(..) 注册回调处理数组(then 方法可被同一个 promise 调用多次)
  4. Promise里的关键是要保证,then方法传入的参数 onFulfilled 和 onRejected,必须在then方法被调用的那一轮事件循环之后的新执行栈中执行。

真正的链式 Promise 是指在当前 Promise 达到 Fulfilled 状态后,即开始进行下一个 Promise。

链式调用

先从 Promise 执行结果看一下,有如下一段代码:

new Promise((resolve, reject) => {
  setTimeout(() => {
      resolve({ test: 1 })
      resolve({ test: 2 })
      reject({ test: 2 })
  }, 1000)
}).then((data) => {
  console.log('result1', data)
}).then((data) => {
  console.log('result2', data)
})
// result1 { test: 1 }
// result2 undefined

显然这里输出了不同的 data。由此可以看出几点:

  1. 可进行链式调用,且每次 then 返回了新的 Promise,2 次打印结果不一致,如果是同一个实例,打印结果应该一致。

  2. 只输出第一次 resolve 的内容,reject 的内容没有输出。

    即 Promise 是有状态且状态只可以由 pending -> fulfilledpending-> rejected是不可逆的。

  3. then 中返回了新的 Promise,但是 then 中注册的回调仍然是属于上一个 Promise 的。

也就是说当一个 Promise 的状态被 fulfilled 之后,会执行其回调函数,而回调函数返回的结果会被当作 value,返回给下一个 Promise ( 也就是 then 中产生的 Promise ),同时下一个 Promise 的状态也会被改变(执行 resolvereject),然后再去执行其回调。

Promise 的核心实现如下:

function Promise(fn) { 
    let state = 'pending';
    let value = null;
    const callbacks = []; // 只 push 和 shift ,用作回调队列
		
		this.then = function (onFulfilled,onRejected) {
      return new Promise((resolve, reject) => {
// handle 作为桥梁,将新 Promise 的 resolve、reject 方法,**放到前一个 promise 的回调对象中**
        handle({
            onFulfilled, 
            onRejected,
            resolve, 
            reject
        })
      })
    }
		/*
		  最关键的点就是在 then 中 **新创建的 Promise**,
      它的状态变为 fulfilled 是在上一个 Promise 的回调执行完毕的时候。
    */
		this.catch = function (onError) {
	    return this.then(null, onError)
	  }
	
		/*
	在实际应用的时候,我们很容易会碰到这样的场景,不管 Promise 最后的状态如何,都要执行一些最后的操作。我们把这些操作放到 finally 中,也就是说 finally 注册的函数是与 Promise 的状态无关的,不依赖 Promise 的执行结果。所以我们可以这样写 finally 的逻辑:
		*/
	  this.finally = function (onDone) {
	    this.then(onDone, onDone)
	  }

		function handle(callback) {
        if(state === 'pending') {
            callbacks.push(callback)
            return;
        }
        
        const cb = state === 'fulfilled'
				  ? callback.onFulfilled
					: callback.onRejected;
        const next = state === 'fulfilled'
					? callback.resolve
					: callback.reject;

        if(!cb){
            next(value)
            return;
        }
				/* **异常处理:**
					异常通常是指在执行成功/失败回调时代码出错产生的错误,
					对于这类异常,我们使用 try-catch 来捕获错误,
					并将 Promise 设为 rejected 状态即可。
				**** */
				let ret;
        try {
            ret = cb(value)
            next(ret)
        } catch (e) {
            callback.reject(e)
        }
				callback.resolve(ret)
    }
    
		// 一个是传给 Promise 入参 fn 的 resolve 函数
		function resolve(newValue) {
	    const fn = () => {
	      if (state !== 'pending') return
	
	      if (newValue 
						&& (typeof newValue === 'object' 
								|| typeof newValue === 'function')
				) {
	        const { then } = newValue
	        if (typeof then === 'function') {
    // newValue 为新产生的 Promise,此时resolve为上个 promise 的resolve
    // 相当于调用了新产生 Promise 的then方法,注入了上个 promise 的resolve 为其回调
	          then.call(newValue, resolve, reject)
	          return
	        }
	      }
	      state = 'fulfilled'
	      value = newValue
	      handelCallback()
	    }
	
	    setTimeout(fn, 0)
	  }
		// 一个是 Promise.resolve 静态方法
		this.resolve = function (value) {
			if (value && value instanceof Promise) {
				return value
			}
      // 如果这个 value 是 `thenable` 的(含有 then() 方法)
			if (value 
		      && typeof value === 'object'
          && typeof value.then === 'function'
			) {
				const { then } = value
				return new Promise((resolve) => {
					then(resolve)
				})
			}
			if (value) {
				return new Promise(resolve => resolve(value))
			}
			return new Promise(resolve => resolve())
		}

		function reject(error) {
	    const fn = () => {
	      if (state !== 'pending') return
	
	      if (error 
						&& (typeof error === 'object' 
								|| typeof error === 'function')
				) {
	        const { then } = error
	        if (typeof then === 'function') {
	          then.call(error, resolve, reject)
	          return
	        }
	      }
	      state = 'rejected'
	      value = error
	      handelCallback()
	    }
	    setTimeout(fn, 0)
	  }
		this.reject = function (value) {
	    return new Promise(((resolve, reject) => {
	      reject(value)
	    }))
	  }

		// 传给 Promise 入参 fn 的 reject 函数
		function reject(error) {
      const fn = () => {
        if (state !== 'pending') return

        if (error
						&& (typeof error === 'object' 
								|| typeof error === 'function')
				) {
            const {then} = error
              if (typeof then === 'function') {
                then.call(error,resolve, reject)
                return
            }
        }
        state = 'rejected';
        value = error
        handelCallback()
      }
      setTimeout(fn, 0)
    }
		// Promise.reject 静态方法
		this.reject = function (value) {
	    return new Promise(((resolve, reject) => {
	      reject(value)
	    }))
	  }
    
    function handelCallback() {
      while (callbacks.length) {
        const fulfiledFn = callbacks.shift();
        handle(fulfiledFn);
      };
    }

		this.catch = function (onError) {
	    return this.then(null, onError)
	  }
	
	  this.finally = function (onDone) {
	    this.then(onDone, onError)
	  }
    
    fn(resolve, reject)
}

Promise.all 实现

入参是一个 Promise 的实例数组,然后注册一个 then 方法,然后是数组中的 Promise 实例的状态都转为 fulfilled 之后则执行 then 方法。

这里主要就是一个计数逻辑,每当一个 Promise 的状态变为 fulfilled 之后就保存该实例返回的数据,然后将计数减一,当计数器变为 0 时,代表数组中所有 Promise 实例都执行完毕。

function Promise(fn){ 
  ...
  this.all = function (arr) {
    let args = Array.prototype.slice.call(arr)
    return new Promise(function (resolve, reject) {
      if (args.length === 0) return resolve([]);
      let remaining = args.length
	
      function done(i, val) {
        try {
          if (val && typeof val === 'object') {
            if(typeof val.then === 'function') {
                val.then.call(
									val, 
									function(val) {
                    done(i, val)
                  },
									reject
								)
                return
            }
          }
          args[i] = val;
          if(--remaining === 0) {
              resolve(args)
          }
        } catch(excetion) {
          reject(excetion)
        }
      }
      for(var i = 0; i < args.length; i++) {
        done(i, args[i])
      }
    });
  }
  ...
}

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×