什麼是 Promise?解決哪些問題?node
ES6 將其寫進了語言標準,統一了用法,原生提供了 Promise 對象。npm
// 定義三種狀態 const REJECTED = 'REJECTED'; const FULFILLED = 'FULFILLED'; const PENDING = 'PENDING'; /** * 判斷一個變量是不是 Promise 的函數 * 1. 是不是對象而且不是 null * 2. 是否有 then 屬性而且 then 是一個方法 * @param {*} val */ function isPromise(val) { if (typeof val === 'object' && val !== null || typeof val === 'function') { return typeof val.then === 'function'; } return false; } console.log('--------------------- MY Promise ---------------------'); // 實現鏈式調用 /** * 處理 then 中的成功、失敗回調函數返回值是不是 Promise 的狀況 * @param {*} promise2 參見 Promise A+ 規範說明 new Promise * @param {*} x 是成功、失敗回調的返回值 */ const resolvePromise = (promise2, x) => { const { resolve, reject } = promise2; // 這裏的判斷是可能本身的 Promise 要和別人的 Promise 混用,可能不一樣的 Promise 庫之間相互調用 // 若是 new 出來的 Promise2 和 x 是同一個,那麼 x 永遠不能成功或者失敗,因此卡死了,直接報錯 if (promise2 === x) return reject(new TypeError('Chaining cycle detected for promise #<Promise>')); // 須要判斷 x 的狀態,判斷 x 是否是 Promise // 先判斷是否是對象或者函數 if (typeof x === 'object' && x !== null || typeof x === 'function') { let called; // 這裏考慮別人的 Promise 是否健壯,不健壯須要再判斷一下,調用了成功就不能失敗,調用的失敗就不能成功。不能屢次調用成功或者失敗 try { const then = x.then; // 內部可能拋出錯誤 // 若是 then 不是函數就說明是一個普通值,直接返回 x if (typeof then !== 'function') resolve(x); // 好比:{ then: 'mhq' } else { // 這裏不要再次調用 x.then 是防止取 then 的時候報錯,萬一 then 方法裏面拋出了一個錯誤呢? then.call(x, y => { if (called) return; called = true; // 若是 x 是一個 Promise,那麼就繼續解析成功的值 resolvePromise(promise2, y); }, f => { if (called) return; called = true; reject(f); // 直接調用 r 做爲失敗的結果 }); } } catch(err) { if (called) return; called = true; reject(err); } } else { resolve(x); } }; class Promise { constructor(executor) { // Promise 的狀態 this.status = PENDING; // 成功後的值 this.value = undefined; // 失敗後的值 this.reason = undefined; // 成功回調函數,發佈訂閱 this.onResolvedCallbacks = []; // 失敗回調函數,發佈訂閱 this.onRejectedCallbacks = []; /** * Promise 內部提供的 resolve,讓 Promise 的狀態變成成功態,並讓成功回調執行 * @param {*} value */ const resolve = value => { if (value instanceof Promise) { return value.then(resolve, reject); } if (this.status === PENDING) { this.status = FULFILLED; this.value = value; this.onResolvedCallbacks.forEach(fn => fn()); } }; /** * Promise 內部提供的 reject,讓 Promise 的狀態變成失敗態,並讓失敗回調執行 * @param {*} reason */ const reject = reason => { if (this.status === PENDING) { this.status = REJECTED; this.reason = reason; this.onRejectedCallbacks.forEach(fn => fn()); } }; // try + catch 只能捕獲同步異常 try { executor(resolve, reject); } catch(err) { reject(err); } } // 只要 x 是一個普通值,就會讓一個 Promise 變成成功態 // 這個 x 有多是一個 Promise,須要菜喲個這個 Promise 的狀態 then(onFulfilled, onRejected) { // 好比.then().then().then(() => {}); 這種調用,對可選參數的處理,透傳 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val; onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }; const promise2 = new Promise((resolve, reject) => { // 一旦 new 則當即執行 if(this.status === FULFILLED) { setTimeout(() => { promise2.resolve = resolve; promise2.reject = reject; try { const x = onFulfilled(this.value); resolvePromise(promise2, x); } catch (err) { reject(err); } }, 0); } if (this.status === REJECTED) { setTimeout(() => { promise2.resolve = resolve; promise2.reject = reject; try { const x = onRejected(this.reason); resolvePromise(promise2, x); } catch (err) { reject(err); } }, 0); } if (this.status === PENDING) { // 自己是異步的 this.onResolvedCallbacks.push(() => { setTimeout(() => { // 這裏須要加上,不加上跑測試跑不通 promise2.resolve = resolve; promise2.reject = reject; try { const x = onFulfilled(this.value); resolvePromise(promise2, x); } catch (err) { reject(err); } }); }); this.onRejectedCallbacks.push(() => { setTimeout(() => { promise2.resolve = resolve; promise2.reject = reject; try { const x = onRejected(this.reason); resolvePromise(promise2, x); } catch (err) { reject(err); } }); }); } }); return promise2; } /** * Promise 中的 catch 指代的就是 then 沒有成功回調的一個別名而已 * @param {*} errCallback */ catch(errCallback) { return this.then(null, errCallback); } } // 不管如何都會執行,把上一個 then 的結果向下傳遞,若是 finally 中返回了一個 Promise 會等待這個 Promise 執行完成後繼續執行 Promise.prototype.finally = function(callback) { return this.then(val => { return Promise.resolve(callback()).then(() => val); }, (err) => { return Promise.resolve(callback()).then(() => { throw err; }); }); }; // npm install promises-aplus-tests -g // promises-aplus-tests promise.js // 測試本身寫的 Promise 是否符合規範的包 Promise.deferred = () => { const dfd = {}; dfd.promise = new Promise((resolve, reject) => { dfd.resolve = resolve; dfd.reject = reject; }); return dfd; }; /** * Promise.resolve 他會等待裏面的 Promise 執行成功 * @param {*} val */ Promise.resolve = val => { return new Promise((resolve) => { resolve(val); }); }; /** * Promise.reject 不會等待參數中的 Promise 執行完畢 */ Promise.reject = () => { return new Promise((_, reject) => { reject(val); }); }; /** * Promise.all 方法表示等待全部的 Promise 所有成功後纔會執行回調,若是有一個 Promise 失敗則 Promise 就失敗了 * @param {*} promises */ Promise.all = promises => { return new Promise((resolve, reject) => { const res = []; let count = 0; const resolveRes = (index, data) => { res[index] = data; if (++count === promises.length) { resolve(res); } }; for(let i = 0; i < promises.length; i++) { const current = promises[i]; if (isPromise(current)) { current.then((data) => { resolveRes(i, data); }, (err) => { reject(err); }); } else { resolveRes(i, current); } } }); } /** * Promise.race 賽跑,誰是第一個完成的,就用他的結果,若是是失敗這個 Promise 就失敗,若是第一個是成功就是成功 * @param {*} promises */ Promise.race = (promises) => { return new Promise((resolve, reject) => { for(let i = 0; i < promises.length; i++) { let current = promises[i]; if (isPromise(current)) { current.then(resolve, reject); } else { resolve(current); break; } } }); } // 專門給 node 的 api 作的 promisify 方法,如 fs.readFile Promise.promisify = fn => { return (...arg) => { return new Promise((resolve, reject) => { fn(...arg, (err, data) => { if (err) reject(err); resolve(data); }); }); } }; module.exports = Promise;