Promise的簡單實現

gzc發表於2018-01-12

Promise本意是承諾.主要目的是為了解決在需要多個非同步操作的時候.產生的回撥巢狀.在es6沒出來前.用bluebird來實現.與java中的Q模組類似.

Promise物件例項建立的過程中有三種狀態, Pending、Fulfilled、Rejected. Fulfilled與Rejected間不能相互轉換.

promise

promise的使用與原理實現

then

promise.then用於鏈式呼叫,每次執行時都會返回一個新的promise物件

all

接收一個promise陣列,如果狀態都為resolve則返回Promise的resolve狀態,如果某個promise狀態為reject則返回Promise的reject狀態

race

接收一個promise陣列, 比誰跑的快.返回第一完成的Promise狀態

promise功能的簡單實現

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) {
  let self = this
  // 初始化
  self.status = PENDING
  // 定義回撥
  self.onResolvedCallbacks = []
  self.onRejectedCallbacks = []

  function resolve(value) {
    if (value != null && value.then && typeof value.then === 'function') {
      return value.then(resolve, reject)
    }
    // 如果是初始狀態.則改變成成功狀態
    setTimeout(() => {
      if (self.status === PENDING) {
        self.status = FULFILLED
        self.value = value
        // 呼叫所有的成功
        self.onResolvedCallbacks.forEach(cb => cb(self.value))
      }
    })
  }

  function reject(reason) {
    setTimeout(() => {
      if (self.status === PENDING) {
        self.status = REJECTED
        self.value = reason
        self.onRejectedCallbacks.forEach(cb => cb(self.value))
      }
    })
  }
  try {
    // 捕獲函式執行時出現的異常
    executor(resolve, reject)
  } catch(e) {
    reject(e)
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('迴圈引用'))
  }
  let called = false
  if (x instanceof Promise) {
    if (x.status === PENDING) {
      x.then(function(y){
        resolvePromise(promise2, y, resolve, reject)
      }, reject)
    } else {
      x.then(resolve, reject)
    }
  } else if(x != null && ((typeof x === 'object') || (typeof x.then === 'function'))) {
    // 相容性處理
    consoole.log('相容性處理')
    try {
      let then = x.then
      if (typeof then === 'function') {
        then.call(x, (y) => {
          if (called) return
          called = true
          resolvePromise(promise2, y, resolve, reject)
        }, (err) => {
          if (called) return
          called = true
          reject(err)
        })
      } else {
        resolve(x)
      }
    } catch(e) {
      if (called) return
      called = true
      reject(e)
    }
  } else {
    // x是一個普通的值
    resolve(x)
  }
}

Promise.prototype.then = function(onFulfilled, onRejected) {
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(value) {return value}
  onRejected = typeof onRejected === 'function' ? onRejected : function(reason) {throw reason}
  let self = this
  let promise2
  if (self.status == FULFILLED) {
    return  promise2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        try {
          let x = onFulfilled(self.value);
          //如果獲取到了返回值x,會走解析Promise的過程
          resolvePromise(promise2, x, resolve, reject);
        } catch(e) {
          //如果執行成功的回撥過程中出錯了,用錯誤原因把Promise2 reject
          reject(e);
        }
      })
    })
  }
  if (self.status == REJECTED) {
    return  promise2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        try {
          let x = onRejected(self.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch(e) {
          reject(e);
        }
      })
    })
  }
  if(self.status == PENDING){
    return promise2 = new Promise(function(resolve,reject){
      self.onResolvedCallbacks.push(function(){
          try{
            let x =onFulfilled(self.value);
            //如果獲取到了返回值x,會走解析promise的過程
            resolvePromise(promise2,x,resolve,reject);
          }catch(e){
            reject(e);
          }
 
      });
      self.onRejectedCallbacks.push(function(){
          try{
            let x =onRejected(self.value);
            resolvePromise(promise2,x,resolve,reject);
          }catch(e){
            reject(e);
          }
      });
    });
   }
}

Promise.prototype.catch = function(onRejected) {
  this.then(null, onRejected)
}

Promise.race = function(promises) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(resolve, reject)
    }
  })
}

Promise.deferred = Promise.defer = function(){
  let defer = {};
  defer.promise = new Promise((resolve,reject) => {
    defer.resolve = resolve;
    defer.reject = reject;
  });
  return defer;
}
Promise.resolve = function (value) {
  return new Promise((resolve, reject) => resolve(value))
}
Promise.reject = function (reason) {
  return new Promise((resolve, reject) => reject(reason))
}

Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    let done = gen(promises.length, resolve)
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(val => {
        done(i, val)
      }, reject)
    }
  })
}

function gen(i, val) {
  let count = 0, result = []
  return function (i, val) {
    result[i] = val
    if (++count === i) {
      resolve(result)
    }
  }
}

module.exports = Promise

複製程式碼

相關文章