源碼的主要實現(xiàn)原理:
1.status三種狀態(tài)的控制;
- then驅(qū)動式遞歸返回promise實現(xiàn)鏈式調(diào)用
- onFulfilled 和 onRejected 必須是setTimeOut模擬異步的確保handle時時異步的,
(更具有標準性,保證每個promise.then執(zhí)行都是異步性,會損可忽略的性能)
實際上源碼的handle異步處理比setTimeOut等級更高
var Promise = (function () {
function Promise(executor) {
// 初始狀態(tài)
this.state = 'pending';
// 成功后必須有一個終值
this.value = undefined;
// 失敗后必須有一個據(jù)因
this.reason = undefined;
// 成功時的回調(diào)函數(shù)集
this.onFulfilledSucc = [];
// 失敗的回調(diào)函數(shù)集
this.onRejectedFail = [];
var _this = this;
var resolve = function (value) {
if (_this.state === 'pending') {
_this.state = 'fulfilled'
_this.value = value;
// 執(zhí)行回調(diào)函數(shù)集中的函數(shù)
_this.onFulfilledSucc.forEach(function (fuc) {
fuc();
});
}
}
var reject = function (reason) {
if (_this.state === 'pending') {
_this.state = 'rejected';
_this.reason = reason;
// 執(zhí)行回調(diào)函數(shù)集中的函數(shù)
_this.onRejectedFail.forEach(function (fuc) {
fuc();
});
}
}
// executor執(zhí)行發(fā)生錯,則直接reject
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
function resolvePromise(promise2, x, resolve, reject) {
// 如果 x === promise2,則會造成循環(huán)引用
if (x === promise2) {
return reject(new TypeError('Chaining cycle detected for promise!'))
}
// 防止多次調(diào)用
var called;
// x不是null 且x是對象或者函數(shù)
if (x != null && (typeof x === 'object') || (typeof x === 'function')) {
try {
// 把 x.then 賦值給 then
var then = x.then;
// 如果then是函數(shù),就默認是x是promise了
if (typeof then === 'function') {
// 如果 then 是函數(shù),將 x 作為函數(shù)的作用域 this 調(diào)用之。
then.call(x, function (y) {
// 成功和失敗只能調(diào)用一個
if (called) return;
called = true;
// 如果 resolvePromise 以值 y 為參數(shù)被調(diào)用,則運行 [[Resolve]](promise, y)
resolvePromise(promise2, y, resolve, reject);
}, function (r) {
if (called) return;
called = true;
// 如果 rejectPromise 以據(jù)因 r 為參數(shù)被調(diào)用,則以據(jù)因 r 拒絕 promise
reject(r);
});
} else {
resolve(x);
}
} catch (e) {
// 如果取 x.then 的值時拋出錯誤 e ,則以 e 為據(jù)因拒絕 promise
if (called) return;
called = true;
reject(e);
}
} else {
// 如果 x 不為對象或者函數(shù),以 x 為參數(shù)執(zhí)行 promise
resolve(x);
}
}
// 原型方法
Promise.prototype.then = function (onFulfilled, onRejected) {
// 如果onFulfilled不是函數(shù),其必須被忽略
onFulfilled = typeof onFulfilled === 'function'
? onFulfilled : function (value) { return value };
// 如果onRejected不是函數(shù),其必須被忽略
onRejected = typeof onRejected === 'function'
? onRejected : function (err) { throw err };
var _this = this;
var promise2 = new Promise(function (resolve, reject) {
if (_this.state === 'fulfilled') {
// 規(guī)定onFulfilled或onRejected不能同步被調(diào)用,必須異步調(diào)用。
setTimeout(function () {
try {
var x = onFulfilled(_this.value);
// 根據(jù)x的值修改promise2的狀態(tài)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (_this.state === 'rejected') {
setTimeout(function () {
try {
var x = onRejected(_this.reason);
// 根據(jù)x的值修改promise2的狀態(tài)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (_this.state === 'pending') {
// onFulfilled傳入到成功時的回調(diào)函數(shù)集
_this.onFulfilledSucc.push(function () {
setTimeout(function () {
try {
var x = onFulfilled(_this.value);
// 根據(jù)x的值修改promise2的狀態(tài)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
// onRejectedFail傳入到失敗時的回調(diào)函數(shù)集
_this.onRejectedFail.push(function () {
setTimeout(function () {
try {
var x = onRejected(_this.reason);
// 根據(jù)x的值修改promise2的狀態(tài)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
});
}
});
return promise2;
}
// Promise.prototype.catch方法是.then(null, rejection)或
// .then(undefined, rejection)的別名,用于指定發(fā)生錯誤時的回調(diào)函數(shù)。
Promise.prototype.catch = function (fn) {
return this.then(null, fn);
}
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) {
return new Promise(function (resolve, reject) {
var promiseLen = promises.length;
var resolvedCounter = 0;
var resolvedValues = new Array(promiseLen);
for (var i = 0; i < promiseLen; i++) {
(function (i) {
Promise.resolve(promises[i]).then(function (value) {
resolvedCounter++;
resolvedValues[i] = value;
if (resolvedCounter == promiseLen) {
return resolve(resolvedValues);
}
}, function (reason) {
return reject(reason);
});
})(i);
}
});
}
Promise.race = function (promises) {
return new Promise(function (resolve, reject) {
for (var i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then(function (value) {
return resolve(value);
}, function (reason) {
return reject(reason);
});
}
});
}
return Promise;
})();
Promise.defer = Promise.deferred = function () {
let dfd = {}
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
module.exports = Promise;
實現(xiàn)多個異步任務(wù)的加載,限制并行加載的數(shù)量,最后返回所有加載的結(jié)果
const waits = [3000, 4000, 200, 8000, 10000, 2000, 1000, 5000]
function loadSync(wait) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(wait)
}, wait)
})
};
function limitLoad(urls, handler, limit) {
const sequence = [].concat(urls)
let promises = [];
const result = [];
promises = sequence.splice(0, limit).map((url, index) => {
return handler(url).then((d) => {
result.push(d);
return index
});
});
return sequence.reduce((last, url, currentIndex) => {
return last.then(() => {
return Promise.race(promises)
}).catch(err => {
console.error(err)
}).then((res) => {
promises[res] = handler(sequence[currentIndex]).then((d) => { result.push(d); return res });
})
}, Promise.resolve()).then(() => {
// 假設(shè)有8個異步,實際才執(zhí)行raise5次得到Top的結(jié)果,需要將最后三個執(zhí)行完再返回總結(jié)果
return Promise.all(promises).then(() => {
return Promise.resolve(result)
})
})
}
limitLoad(waits, loadSync, 3).then(d => {
console.log(d, "data")
})