點我看看~
前言:可能存在闡述不準確之處,歡迎指正~
Promise在long time ago就活躍於Javascript社區,受到開發者歡迎,只不過到近幾年才被納入ECMA規範。
我們為什麼要使用Promsie?
因為:
我們不希望,過了幾個月之後,代碼只有上帝才看得懂;
我們不希望,回調代碼越寫越往右,只能換更大的顯示器看;
我們希望,哪怕過了很久,代碼依舊邏輯清晰,看懂不費吹灰之力;
我們希望,能夠用自己的雙手,控制住異步流的動向,就像同步代碼一樣;
有逼格...
(歡迎補充)
話不多説,上源碼(採用es6/es7, 創建一個Commitment類模仿Promise)::
class Commitment {
constructor (executor) {
this.status = "pending";
this.value = void(0);
this.reason = void(0);
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (value instanceof Promise) {
return value.then(resolve, reject)
}
setTimeout(() => {
if (this.status === "pending") {
this.status = "resolved";
this.value = value;
this.onResolvedCallbacks.forEach(cb => cb(value));
}
})
}
const reject = (reason) => {
setTimeout(() => {
if (this.status === "pending") {
this.status = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach(cb => cb(reason));
}
})
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then (onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
onRejected = typeof onRejected === "function" ? onRejected : reason => {
throw reason
};
const resolveCommitment = (Commitment2, x, resolve, reject) => {
if (Commitment2 === x) {
return reject(new TypeError("A promise cannot be resolved with itself"))
}
let then, called;
if (x !== null && (typeof x === "object" || typeof x === "function")) {
try {
then = x.then;
if (typeof then === "function") {
then.call(x, y => {
if (called) return
called = true;
resolveCommitment(Commitment2, y, resolve, reject);
}, r => {
if (called) return
called = true;
reject(r)
})
} else {
resolve(x)
}
} catch (e) {
if (called) return
called = true;
reject(e)
}
} else {
resolve(x)
}
}
let Commitment2, x;
if (this.status === "resolved") {
Commitment2 = new Commitment((resolve, reject) => {
setTimeout(() => {
try {
x = onFulfilled(this.value);
resolveCommitment(Commitment2, x, resolve, reject)
} catch (e) {
reject(e)
}
});
})
}
if (this.status === "rejected") {
Commitment2 = new Commitment((resolve, reject) => {
setTimeout(() => {
try {
x = onRejected(this.reason);
resolveCommitment(Commitment2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
if (this.status === "pending") {
Commitment2 = new Commitment((resolve, reject) => {
this.onResolvedCallbacks.push((value)=> {
try {
x = onFulfilled(value);
resolveCommitment(Commitment2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
this.onRejectedCallbacks.push((reason) => {
try {
x = onRejected(reason);
resolveCommitment(Commitment2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
return Commitment2
}
}