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規範
Promises/A+規範(英文版)
Promises/A+規範(中文版)測試
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的可迭代對象(好比數組),只有當可迭代對中全部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(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 = function(data) { return new Promise((resolve, reject) => { resolve(data) }) } //測試用例 var p1 = Promise.resolve(123); p1.then(function(value) { console.log(value); }); //123
Promise.reject(reason)方法返回一個帶有拒絕緣由reason參數的Promise對象。
Promise.resolve = function(data) { return new Promise((resolve, reject) => { reject(data) }) }