參考:Prmoises A+規範node
function Promise(fn) { var _this = this; var callback = null; this._value = null; // 存放resolve(解決)的結果 this._reason = null; // 存放reject(拒絕)的緣由 this._onResolveds = []; // 存放resolve前調用then時傳入的函數onResolved(可能屢次調用then,因此是數組) this._onRejecteds = []; // 存放reject前調用catch時傳入的函數onRejected(可能屢次調用catch,因此是數組) this._status = "pending"; function resolve(val) { if (_this._status !== 'pending') { // 若status已經改變爲"resolved"或"rejected",回調直接在then內處理 return } _this._value = val; _this._status = "resolved"; while (callback = _this._onResolveds.shift()) { // 按註冊順序依次執行回調 callback(val) } } function reject(reason) { if (_this._status !== 'pending') { return } _this._reason = reason; _this._status = "rejected"; while (callback = _this._onRejecteds.shift()) { callback(reason) } } try { fn(resolve, reject) } catch (err) { reject(err) } }
Promise.prototype.then = function (onResolved, onRejected) { // 規範:若是 onFulfilled 不是函數,其必須被忽略 // 這裏,若onResolved, onRejected 不是函數,則用一個過渡性的函數代替 onResolved = typeof onResolved === 'function'? onResolved:function(value) { return value; // 將value原封不動地傳給下一個then,至關於跳過(忽略)本輪then的onResolved } onRejected = typeof onRejected === 'function'? onRejected:function(err) { throw err; // 同上,至關於跳過(忽略)本輪then的onRejected } var _this = this var promise2 // then始終返回一個Promise實例,用於鏈式調用。 if (_this._status === "resolved") { promise2 = new Promise(function (resolve, reject){ setTimeout(function() { // 確保onResolved 和 onRejected 方法異步執行。下面的setTimeout同理 try { var x = onResolved(_this._value) resolvePromise(promise2, x, resolve, reject) // resolvePromise內執行promise2的resolve和reject } catch (e) { reject(e) } }, 0); }) } if (_this._status === "rejected") { promise2 = new Promise(function (resolve, reject){ setTimeout(function() { try { var x = onRejected(_this._reason) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0); }) } if (_this._status === "pending") { // resolve或reject前調用then的話,將回調推入隊列 promise2 = new Promise(function (resolve, reject) { _this._onResolveds.push(function () { setTimeout(function() { try { var x = onResolved(_this._value) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0); }); _this._onRejecteds.push(function () { setTimeout(function() { try { var x = onRejected(_this._reason) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0); }); }) } return promise2 };
function resolvePromise (promise2, x, resolve, reject) { if(promise2 === x) { // 防止引用同一個promise,致使死循環 return reject(new TypeError('循環引用')); } var called = false // 防止屢次調用 if (x!== null && (typeof x ==='object' ||typeof x === 'function')) { try { let then = x.then; if (typeof then === 'function') { // x 是一個定義了 then 方法的對象或函數,即thenable then.call(x, function(y) { // 這裏規範是這樣說明的:這步咱們先是存儲了一個指向 x.then 的引用,而後測試並調用該引用,以免屢次訪問 x.then 屬性。這種預防措施確保了該屬性的一致性,由於其值可能在檢索調用時被改變。 if (called) return // 確保resolve和reject,只執行其中一個 called = true; resolvePromise(promise2, y, resolve, reject) // 若是x是thenable,則繼續調用resolvePromise,直到 onResolved/onRejected 的返回值不是 thenable }, function(err) { if (called) return called = true; reject(err); }) } else { resolve(x) // 若是 x 不屬於 thenable, 則把x做爲返回值. } } catch (e) { if (called) return called = true; reject(e) } } else { //普通值 resolve(x) } }
Promise.prototype.catch = function (onRejected) { return this.then(undefined, onRejected) }
Promise.resolve = function (value) { return new Promise(function (resolve, reject) { resolve(value) }) }
Promise.reject = function (reason) { return new Promise(function (resolve, reject) { reject(reason) }) }
Promise.all = function (promises) { if (!Array.isArray(promises)) { throw new TypeError('必須傳入promise數組'); } var length = promises.length var values = [] return new Promise(function (resolve, reject) { function rejectHandle(reason) { reject(reason) // 只要其中一個reject,總體reject } function resolveHandle(index) { return function (value) { values[index] = value // 按傳入時的順序記錄每一個promise的結果值 if (--length === 0) { // 全部子promise都resolve後,總體resolve resolve(values) } } } promises.forEach(function (item, index) { item.then(resolveHandle(index), rejectHandle) }) }) }
Promise.race = function (promises) { if (!Array.isArray(promises)) { throw new TypeError('必須傳入promise數組'); } return new Promise(function (resolve, reject) { function rejectHandle(reason) { reject(reason) } function resolveHandle(value) { resolve(value) } promises.forEach(function (item) { item.then(resolveHandle, rejectHandle) }) }) }
// 無論resolved仍是rejected,都會執行,避免一樣的語句須要在then()和catch()中各寫一次的狀況。 Promise.prototype.finally = function (callback) { return this.then(callback, callback) }
使用promises-aplus-tests
:全局安裝npm i promises-aplus-tests -g
,而後命令行 promises-aplus-tests [js文件名]
進行測試npm
注意:測試前要在尾部加上下面的代碼:數組
Promise.deferred = Promise.defer = function () { let deferred = {}; deferred.promise = new Promise(function (resolve, reject) { deferred.resolve = resolve; deferred.reject = reject; }); return deferred }; module.exports = Promise
測試完成後可刪除promise
(function (global, factory) { if (typeof define === 'function' && define.amd) { // AMD define(factory) } else if (typeof exports === 'object' && typeof module !== 'undefined') { // CommonJS (如node) module.exports = factory() } else { // 瀏覽器全局變量 global.promisePolyfill = factory() } })(this, function () { 'use strict'; /* 定義Promise的代碼 */ function promisePolyfill () { var global = null try { global = Function('return this')(); } catch (e) { throw new Error('全局對象不可用'); } global.Promise = Promise } return promisePolyfill })
promisePolyfill() // 註冊Promise全局變量