從promise-polyfill.js實現看Promise應用時注意點
resolve/reject只能接收一個傳值
工作中封裝一個ajax請求簡寫方法,想API返回正常情況值時(code===200
),直接.then裡呼叫data資料.異常時,在catch裡傳遞三個引數msg, code, date.
寫完後,發現.catch後面兩個引數呼叫時始終是undefined
.網上查了下資料,原來resolve/reject只能接收一個值傳遞.要實現多引數只能變相通過物件或陣列來顯現.
//https://github.com/taylorhakes/promise-polyfill/blob/master/dist/polyfill.js#L149 function doResolve(fn, self) { var done = false; try { fn( function(value) {//只接收一個傳值 if (done) return; done = true; resolve(self, value); }, function(reason) {//只接收一個傳值 if (done) return; done = true; reject(self, reason); } ); } catch (ex) { if (done) return; done = true; reject(self, ex); } } //https://github.com/taylorhakes/promise-polyfill/blob/master/dist/polyfill.js#L85 function resolve(self, newValue) { try { if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.'); if ( newValue && (typeof newValue === 'object' || typeof newValue === 'function') ) { var then = newValue.then; if (newValue instanceof Promise) { self._state = 3; self._value = newValue; finale(self); return; } else if (typeof then === 'function') { doResolve(bind(then, newValue), self); return; } } // 上面邏輯解決傳遞值是一個promise時,則獲取該promise決議值 self._state = 1; self._value = newValue;//儲存供第一次then呼叫 finale(self); } catch (e) { reject(self, e); } } function reject(self, newValue) { self._state = 2; self._value = newValue;//儲存值待第一次then(null, reject)/catch呼叫 finale(self); } /* 下面是常用寫法,promise-polyfill.js 呼叫棧Promise -> doResolve -> resolve/reject . fn中的兩個函式,顯然值接收了一個引數value(reject為reason), 接著在函式內呼叫resolve/reject,將值用self._value儲存. 後續then`第一次`呼叫則引用self._value值. new Promise(fuction(resolve, reject)) { ...... resolve(...args) ...... reject(...args) ...... }).then() */
鏈式呼叫或return一個已使用then的promise,需在前一個then/catch中顯示return value
then/catch忽略非函式值,返回呼叫前的promise(含值)
catch後續呼叫then,則返回一個新promise,結果為其callback執行結果(異常情況,走後續catch).
// https://github.com/taylorhakes/promise-polyfill/blob/master/dist/polyfill.js#L175 Promise.prototype.then = function(onFulfilled, onRejected) { var prom = new this.constructor(noop); handle(this, new Handler(onFulfilled, onRejected, prom));//新的promise,供後面返回 return prom; }; // https://github.com/taylorhakes/promise-polyfill/blob/master/dist/polyfill.js#L137 // 非函式值,轉換為null function Handler(onFulfilled, onRejected, promise) { this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; this.onRejected = typeof onRejected === 'function' ? onRejected : null; this.promise = promise; } //https://github.com/taylorhakes/promise-polyfill/blob/master/dist/polyfill.js#L59 function handle(self, deferred) { while (self._state === 3) { self = self._value; } if (self._state === 0) { self._deferreds.push(deferred); return; } self._handled = true; Promise._immediateFn(function() { var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected; if (cb === null) {//如果resolve或reject非函式值,則使用前promise (self._state === 1 ? resolve : reject)(deferred.promise, self._value); return; } var ret; try { ret = cb(self._value);// catch結果不拋錯,作為新promise的resolve值 } catch (e) { reject(deferred.promise, e); return; } resolve(deferred.promise, ret);// 如果cb沒有返回值,則ret為undefined,傳給下個promise });// 即promise.then(calback).then(callback(undefind){...}) }
finally無接收值,返回一個新promise含原promise決議值.(finally callback執行無error)
//https://github.com/taylorhakes/promise-polyfill/blob/master/dist/polyfill.js#L10 function finallyConstructor(callback) { var constructor = this.constructor; return this.then( function(value) { return constructor.resolve(callback()).then(function() { return value; }); }, function(reason) { return constructor.resolve(callback()).then(function() { return constructor.reject(reason); }); } ); }
catch與then(null, reject)不完全相同.
如果then中resolve出現異常,則後續的catch處理該異常,非原先promise的reject