前言:可能存在阐述不准确之处,欢迎指正~
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 }}