面試會遇到Promise,問你是怎麼理解Promise的?git
個人理解就是承諾!es6
編碼代碼,存在異步的地方都會遇到Promise! 搞了這麼久,感受理解不是很透github
突然想起一句話:學習法語糖的最好方法,是本身去實現ta,本身實現不了,就看比人怎麼實現的面試
let promise = new Promise( function(resolve, reject) {
/* 異步操做 */ setTimeout(() => {
let number = Math.floor(Math.random() * 3)
if (number == 2) {
resolve(number);
} else {
reject('不是2')
}
}, 3000);
} )
promise.then(
(value) => {// then方法第一個參數onFulfilled,異步任務成功時調用
console.log(value);
},
(value) => {// then方法第二個參數onRejected,異步任務成功時調用
console.log(value);
}
);
複製代碼
function Promise(fn) {
//校驗
if (!(this instanceof Promise))
throw new TypeError('Promise 前面必須加new');
if (typeof fn !== 'function') throw new TypeError('not a function');
this._state = 0; // _state有三個值 0表明PENDING(進行中)
//1表明FULFILLED (已成功)
//2表明REJECTED(已失敗)
//3表明傳入resolve的是Promise實例
this._value = undefined; //異步任務完成獲取的值 reslove()或者reject()中傳遞的值
this._deferreds = []; //存放then函數傳遞的回調
doResolve(fn, this);
}
複製代碼
根據上面的例子能夠看到Promise構造函數的參數是一個包含異步任務的函數數組
有了構造函數,接下來實現doResolve(fn, this),doResolve要作兩件事,第一要執行咱們傳入的promise
包含異步任務的函數,同時傳入resolve,reject參數 function(resolve, reject) {,能夠看上線的例子bash
function doResolve(fn, self) {
var done = false;
fn(
function(value) { //第一個參數resolve,當異步成功完成調用
if (done) return;
done = true;
resolve(self, value);
},
function(reason) { //第二個參數reject,當異步完成失敗調用
if (done) return;
done = true;
reject(self, reason);
}
);
}
複製代碼
其中利用閉包,保證傳入的resolve,reject 只能調用一次,保持對self,Promise實例的引用閉包
接下來實現resolve,reject,方法只是記錄下_state的狀態dom
function resolve(self, newValue) {
self._state = 1;
self._value = newValue;
finale(self);
}
function reject(self, newValue) {
self._state = 2;
self._value = newValue;
finale(self);
}複製代碼
實現finale,調用self._deferreds 存放then方法中傳入的回調onFulfilled和onRejected異步
再沒有調用then方法時,self._deferreds=[],當調用then 方法時判斷self._state === 0是沒有完成
就將then 方法的回調存入self._deferreds,若是已經完成,根據self._state爲1或者2調用onFulfilled或者onRejected
function finale(self) {
for (var i = 0, len = self._deferreds.length; i < len; i++) {
handle(self, self._deferreds[i]);
}
self._deferreds = null;
}
function handle(self, deferred) {
if (self._state === 0) {
self._deferreds.push(deferred);
return;
}
setTimeout(function() {
var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
cb(self._value);
}, 0);
}複製代碼
實現then方法,當調用then 方法時判斷self._state === 0是沒有完成
就將then 方法的回調存入self._deferreds,若是已經完成,根據self._state爲1或者2調用onFulfilled或者onRejected
Promise.prototype.then = function(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
onRejected = typeof onRejected === 'function' ? onRejected : null;
handle(this, {onFulfilled,onRejected});
}複製代碼
基本的Promise就實現了,去掉不少細節
Promise.prototype.catch = function(onRejected) {
return this.then(null, onRejected);
};
Promise.resolve = function(value) {
if (value && typeof value === 'object' && value.constructor === Promise) {
return value;
}
return new Promise(function(resolve) {
resolve(value);
});
};
Promise.reject = function(value) {
return new Promise(function(resolve, reject) {
reject(value);
});
};
Promise.race = function(values) {
return new Promise(function(resolve, reject) {
for (var i = 0, len = values.length; i < len; i++) {
values[i].then(resolve, reject);
}
});
};
複製代碼
這幾個方法都很簡單,複雜一點的是Promise.all;
Promise.all = function(arr) {
return new Promise(function(resolve, reject) {
if (!arr || typeof arr.length === 'undefined')
throw new TypeError('Promise.all accepts an array');
var args = Array.prototype.slice.call(arr);
if (args.length === 0) return resolve([]);
var remaining = args.length;
function res(i, val) {
try {
if (val && (typeof val === 'object' || typeof val === 'function')) {
var then = val.then;
if (typeof then === 'function') {
then.call(
val,
function(val) {
res(i, val);
},
reject
);
return;
}
}
args[i] = val;
if (--remaining === 0) {
resolve(args);
}
} catch (ex) {
reject(ex);
}
}
for (var i = 0; i < args.length; i++) {
res(i, args[i]);
}
});
複製代碼
Promise.all傳入的是一個Promise實例數組,經過計數方式當傳入的Promise實例每完成一個--remaining,計數器減一,全部都完成了調用resolve觸發then的回調
當你看完實現代碼再結合阮一峯的講解實例es6.ruanyifeng.com/#docs/promi…,應該能夠更快的掌握
本文爲了更好理解,省去了不少代碼完整代碼請查看promise-polyfill