本身動手實現一個Promise

Promise基本用法

Promise 對象是一個代理對象,被代理的值在Promise對象建立時多是未知的。數組

它容許你爲異步操做的成功和失敗分別綁定相應的處理方法(handlers)。 這讓異步方法能夠像同步方法那樣返回值,但並非當即返回最終執行結果,而是一個能表明將來出現的結果的promise對象promise

一個 Promise有如下幾種狀態:異步

pending: 初始狀態,既不是成功,也不是失敗狀態。
fulfilled: 意味着操做成功完成。
rejected: 意味着操做失敗。

pending 狀態的 Promise 對象可能觸發fulfilled 狀態並傳遞一個值給相應的狀態處理方法,也可能觸發失敗狀態(rejected)並傳遞失敗信息。當其中任一種狀況出現時,Promise 對象的 then 方法綁定的處理方法(handlers )就會被調用(then方法包含兩個參數:onfulfilled 和 onrejected,它們都是 Function 類型。當Promise狀態爲fulfilled時,調用 then 的 onfulfilled 方法,當Promise狀態爲rejected時,調用 then 的 onrejected 方法, 因此在異步操做的完成和綁定處理方法之間不存在競爭)。函數

由於 Promise.prototype.then 和 Promise.prototype.catch 方法返回promise 對象, 因此它們能夠被鏈式調用。post

var promise1 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve('foo');
  }, 300);
});

promise1.then(function(value) {
  console.log(value);
  // expected output: "foo"
});

console.log(promise1);
// expected output: [object Promise]

Promise/A+

而後咱們來了解一下Promise規範
Promises/A+規範(英文版)
Promises/A+規範(中文版)測試

Promise的實現

  1. Promise是經過new建立的,能夠經過構造函數模式或者是ES6的class來實現,這兒選擇構造函數的方式來實現Promise,首先先完成一個簡易版本的Promise。
function Promise(exector) {
    var _this = this
    this.status = 'pending'
    this.value = undefined

    try {
      exector(resolve, reject)
    }catch(e) {
      reject(e)
    }

    function resolve(value) {
      if(_this.status === 'pending') {
        _this.status = 'fulfilled'
        _this.value = value
      }
    }

    function reject(value) {
      if(_this.status === 'pending') {
        _this.status = 'rejected'
        _this.value = value
      }
    }
  }

  Promise.prototype.then = function(resolveCallback, rejectCallback) {
    if(this.status === 'fulfilled') {
      resolve(this.value)
    }

    if(this.status === 'rejected') {
      reject(this.value)
    }
  }

  new Promise((resolve, reject)=> {
    resolve('1')
  }).then((data)=> {
    console.log('resolve' + data)
  }, (data)=> {
    console.log('reject' + data)
  }) //resolve1

  new Promise((resolve, reject)=> {
    setTimeout(()=> {
      resolve('1')
    }, 1000)
  }).then((data)=> {
    console.log('resolve' + data)
  }, (data)=> {
    console.log('reject' + data)
  }) //沒法正常輸出

上面這個promise中resolve和reject在同步的狀況下都能正常輸出,可是如今卻不支持異步,由於在異步的時候調用then的時候狀態仍是'pending',因此resolve/reject並不能如期執行。this

這個時候就須要一個存放後續調用事件的數組,當異步函數執行完畢後再執行數組中的函數。prototype

改進後異步方法能夠正常運行:代理

function Promise(exector) {
    var _this = this
    this.status = 'pending'
    this.value = undefined
    this.resolveList = []
    this.rejectList = []

    try {
      exector(resolve, reject)
    }catch(e) {
      reject(e)
    }

    function resolve(value) {
      if(_this.status === 'pending') {
        _this.status = 'fulfilled'
        _this.value = value
        _this.resolveList.forEach(item=> {
          item(_this.value)
          _this.resolveList.shift()
        })
      }
    }

    function reject(value) {
      if(_this.status === 'pending') {
        _this.status = 'rejected'
        _this.value = value
        _this.rejectList.forEach(item=> {
          item(_this.value)
          _this.rejectList.shift()
        })
      }
    }
  }

  Promise.prototype.then = function(resolveCallback, rejectCallback) {
    if(this.status === 'fulfilled') {
      resolve(this.value)
    }

    if(this.status === 'rejected') {
      reject(this.value)
    }

    if(this.status === 'pending') {
      this.resolveList.push(resolveCallback)
      this.rejectList.push(rejectCallback)
    }
  }

  new Promise((resolve, reject)=> {
    setTimeout(()=> {
      resolve('1')
    }, 1000)
  }).then((data)=> {
    console.log('resolve' + data)
  }, (data)=> {
    console.log('reject' + data)
  })

鏈式調用

咱們能夠注意到Promise是能夠鏈式調用的,這就須要then的方法返回一個Promise對象。code

下面是一個鏈式調用的簡單例子:

let promise = new Promise((resolve, reject)=> {
  resolve(666)
})

promise.then(data=> {
  console.log(data)
  return data + 1
}).then(data=> {
  console.log(data)
})
//666
//667

在Promise鏈中返回Promise:

let promise1 = new Promise((resolve, reject)=> {
  resolve(666)
})

let promise2 = new Promise((resolve, reject)=> {
  resolve(999)
})


promise1.then(data=> {
  console.log(data)

  return promise2
}).then(data=> {
  console.log(data)
})
//666
//999

關於這種寫法須要注意的是,第二個完成處理程序被添加到第三個promise而不是return的promise2,上面的例子等價於:

let promise1 = new Promise((resolve, reject)=> {
  resolve(666)
})

let promise2 = new Promise((resolve, reject)=> {
  resolve(999)
})

let promise3 = promise1.then(data=> {
  console.log(data)

  return promise2
})

promise3.then(data=> {
  console.log(data)
})
//666
//999

當異步的時候調用then函數的時候狀態爲pending,這個時候一樣須要返回一個promise方便後續的鏈式調用。

因此修改成鏈式調用後的代碼爲:

function Promise(exector) {
  var _this = this
  this.status = 'pending'
  this.value = undefined
  this.resolveList = []
  this.rejectList = []

  try {
    exector(resolve, reject)
  }catch(e) {
    reject(e)
  }

  function resolve(value) {
    if(_this.status === 'pending') {
      _this.status = 'fulfilled'
      _this.value = value
      _this.resolveList.forEach(item=> {
        item(_this.value)
        _this.resolveList.shift()
      })
    }
  }

  function reject(value) {
    if(_this.status === 'pending') {
      _this.status = 'rejected'
      _this.value = value
      _this.rejectList.forEach(item=> {
        item(_this.value)
        _this.rejectList.shift()
      })
    }
  }
}

Promise.prototype.then = function(resolveCallback, rejectCallback) {
  var _this = this
  if(this.status === 'fulfilled') {
    return new Promise((resolve, reject)=> {
      var result = resolveCallback(_this.value)
      if(result instanceof Promise) {
        result.then(resolve, reject)
      }else {
        resolve(result)
      }
    })
  }

  if(this.status === 'rejected') {
    return new Promise((resolve, reject)=> {
      var result = rejectCallback(_this.value)
      if(result instanceof Promise) {
        result.then(resolve, reject)
      }else {
        reject(result)
      }
    })
  }

  if(this.status === 'pending') {
    return new Promise((resolve, reject)=> {
      _this.resolveList.push(function() {
        var result = resolveCallback(_this.value)
        if(result instanceof Promise) {
          result.then(resolve, reject)
        }else {
          resolve(result)
        }
      })

      _this.rejectList.push(function() {
        var result = rejectCallback(_this.value)
        if(result instanceof Promise) {
          result.then(resolve, reject)
        }else {
          reject(result)
        }

      })

    })
  }
}


new Promise((resolve, reject)=> {
  resolve(666)
}).then((data)=> {
  console.log('resolve1:' + data)
  return 999
}).then((data)=> {
  console.log('resolve2:' + data)
})
//resolve1: 666
//resolve2: 999

new Promise((resolve, reject)=> {
  resolve(666)
}).then((data)=> {
  console.log('resolve1:' + data)
  return new Promise((resolve, reject)=> {
    resolve(999)
  })
}).then((data)=> {
  console.log('resolve2:' + data)
})
//resolve1: 666
//resolve2: 999

基本的功能已經實現,下面開始實現Promise的all,race,resolve,reject方法,鏈式調用部分思路借鑑Promise/A+規範的實現

Promise.all()

該方法只接受一個有多個受監聽的Promise的可迭代對象(好比數組),只有當可迭代對中全部Promise都被解決後纔會返回resolve,若是參數中 promise 有一個失敗,此實例回調失敗(reject),失敗緣由的是第一個失敗 promise 的結果。

Promise.all = function(iterable) {
  return new Promise((resolve, reject) => {
    let result = []
    for(const item of iterable) {
      item.then(data => {
        result.push(data)
      }, reason=> {
        result = reason
        return
      })
    }

    resolve(result)
  })
}

//下面是測試用例
let p1 = new Promise((resolve, reject) => {
  resolve(666)
})

let p2 = new Promise((resolve, reject) => {
  resolve(888)
})

let p3 = new Promise((resolve, reject) => {
  resolve(999)
})

let p6 = new Promise((resolve, reject) => {
  reject(222)
})

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

p4.then(data => {
  console.log(data)
})
//[666, 888, 999]
let p7 = Promise.all([p1, p3, p6])

p7.then(data => {
  console.log(data)
})
//222

Promise.race()

Promise.race(iterable) 方法返回一個 promise,一旦迭代器中的某個promise解決或拒絕,返回的 promise就會解決或拒絕。

Promise.race = function(iterable) {
  return new Promise((resolve, reject) => {
    for(const item of iterable) {
      item.then(data => {
        resolve(data)
      }, reason=> {
        reject(reson)
      })
    }
  })
}
//測試用例
var p1 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 500, 'one');
});

var p2 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 100, 'two');
});

Promise.race([p1, p2]).then(function(value) {
  console.log(value);
  // Both resolve, but promise2 is faster
});
//two

Promise.resolve()

Promise.resolve = function(data) {
  return new Promise((resolve, reject) => {
    resolve(data)
  })
}

//測試用例
var p1 = Promise.resolve(123);

p1.then(function(value) {
  console.log(value);
});
//123

Promise.reject()

Promise.reject(reason)方法返回一個帶有拒絕緣由reason參數的Promise對象。

Promise.resolve = function(data) {
  return new Promise((resolve, reject) => {
    reject(data)
  })
}
相關文章
相關標籤/搜索