Promise 雏形
Promise 构造函数返回一个 promise 对象实例,这个返回的 promise 对象具有一个 then 方法。then 方法中,调用者可以定义两个参数,分别是 onFulfilled 和 onRejected,它们都是函数类型。其中 onFulfilled 通过参数,可以获取 promise 对象 resolved 的值,onRejected 获得 promise 对象 rejected 的值。通过这个值,我们来处理异步完成后的逻辑。
实现
function Promise(executor) {}Promise.prototype.then = function(onfulfilled, onrejected) {}
复习 Promise 的知识,看例子来理解。
let promise1 = new Promise((resolve, reject) => {resolve("data");});promise1.then(data => {console.log(data);});let promise2 = new Promise((resolve, reject) => {reject("error");});promise2.then(data => {console.log(data);}, error => {console.log(error);});
我们可以得到结论,在使用 new 关键字调用 Promise 构造函数时,在合适的时机(往往是异步结束时),调用 executor 的参数 resolve 方法,并将 resolved 的值作为 resolve 函数参数执行,这个值便可以后续在 then 方法第一个函数参数(onFulfilled)中拿到;同理,在出现错误时,调用 executor 的参数 reject 方法,并将错误信息作为 reject 函数参数执行,这个错误信息可以在后续的 then 方法第二个函数参数(onRejected)中拿到。
因此,我们在实现 Promise 时,应该有一个值用于保存 resolve 或者 reject 的值(因为 Promise 状态的唯一性,所以不需要分别用两个变量分别保存);同时也需要存在一个状态,这个状态就是 Promise 实例的状态(pending、fulfilled、rejected);同时还要提供 resolve 方法以及 reject 方法。
function Promise(executor) {let self = this;self.status = "pending";self.value = null;self.onResolveCallbacks = [];self.onRejectCallbacks = [];function resolve(value) {if (self.status === "pending") {self.status = "fulfilled";self.value = value;self.onResolveCallbacks.forEach(cb => cb(self.value));}}function reject(reason) {if (self.status === "pending") {self.status = "rejected";self.value = reason;self.onRejectCallbacks.forEach(cb => cb(self.value));}}try {executor(resolve, reject);} catch (e) {reject(e);}}
有一点需要解释的是,执行 executor 有可能会出错就像下面这样,如果出错了 Promise 应该 reject 这个出错的值。所以需要把 executor 放在 try catch 语句。
new Promise(function(resolve, reject) {throw 2})
实现 then 方法
Promise.prototype.then = function(onFulfilled, onRejected) {let self = thisonFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => vonRejected = typeof onRejected === 'function' ? onRejected : r => {throw r}if (self.status === 'pending') {self.onResolveCallbacks.push(onFulfilled)self.onRejectCallbacks.push(onRejected)}if (self.status === 'fulfilled') {onFulfilled(self.value)}if (self.status === 'rejected') {onRejected(self.value)}}
为了透传我们在 onFulfilled/onRejected 不是一个函数的时候也默认返回一个函数用于返回当前的 onFulfilled/onRejected 的值,当 status 处于 pending 状态,不能确定调用 onFulfilled 还是onRejected,只有等状态确定后才可以处理,所以把两个 callback 存入回调数组,等到状态确认时调用对应的方法。
实现链式调用
在 Promise A+ 规范中有提到过 then 需要返回一个 Promise 实例,这也是可以链式调用的关键。
改写 then 方法
Promise.prototype.then = function (onFulfilled, onRejected) {let self = this;onFulfilled = typeof onFulfilled === "function" ? onFulfilled : v => v;onRejected = typeof onRejected === "function" ? onRejected : r => {throw r;};let returnedPromise = null;if (self.status === "pending") {return returnedPromise = new Promise((resolve, reject) => {self.onResolveCallbacks.push(onFulfilled);self.onRejectCallbacks.push(onRejected);});}if (self.status === "fulfilled") {return returnedPromise = new Promise((resolve, reject) => {onFulfilled(self.value);});}if (self.status === "rejected") {return returnedPromise = new Promise((resolve, reject) => {onRejected(self.value);});}};
根据规范的定义,需要定义一个[Resolve] 解析函数,解析 onFullilled 或 onRejected 的返回值,同时对这两个方法执行期间抛出的错误进行 reject。
// pendingself.onResolveCallbacks.push(() => {try {let x = onFulfilled(self.value);ResolutionProcedure(returnedPromise, x, resolve, reject);} catch (e) {reject(e);}});self.onRejectCallbacks.push(() => {try {let x = onRejected(self.value);ResolutionProcedure(returnedPromise, x, resolve, reject);} catch (e) {reject(e);}});// fullilledtry {let x = onFulfilled(self.value);ResolutionProcedure(returnedPromise, x, resolve, reject);} catch (e) {reject(e);}// rejectedtry {let x = onRejected(self.value);ResolutionProcedure(returnedPromise, x, resolve, reject);} catch (e) {reject(e);}
实现 ResolutionProcedure 方法
function ResolutionProcedure(promise, x, resolvePromise, rejectPromise) {try {if (promise === x) {return rejectPromise(new TypeError("2.3.1"));}if (x instanceof Promise) {x.then((value) => {return ResolutionProcedure(promise, value, resolvePromise, rejectPromise);},(reason) => {return rejectPromise(reason);});}let called = false;if (x !== null && (typeof x === "object" || typeof x === "function")) {try {let then = x.then;if (typeof then === "function") {then.call(x, (value) => {if (called) return;called = true;return ResolutionProcedure(promise, value, resolvePromise, rejectPromise);}, (reason) => {if (called) return;called = true;return rejectPromise(reason);});} else {return resolvePromise(x);}} catch (e) {if (called) return;called = true;return rejectPromise(e);}} else {return resolvePromise(x);}} catch (e) {return rejectPromise(e);}}
解释下面这段代码
if (x instanceof Promise) {x.then((value) => {return ResolutionProcedure(promise, value, resolvePromise, rejectPromise);},(reason) => {return rejectPromise(reason);});}
为什么 then 的两个参数函数的返回值是不同的?
理解这段代码(原生 Promise)
new Promise((resolve, reject) => {resolve("resolve");}).then(res => {console.log(res);return new Promise((resolve, reject) => {resolve(new Promise((resolve, reject) => {resolve("inner resolve");}));});}, err => console.log(err)).then(res => console.log("res", res), err => console.log("err", err));//////////////////////////////new Promise((resolve, reject) => {resolve("resolve");}).then(res => {console.log(res);return new Promise((resolve, reject) => {reject(new Promise((resolve, reject) => {reject("inner resolve");}));});}, err => console.log(err)).then(res => console.log("res", res), err => console.log("err", err));
两段代码的结果


支持异常执行,使用 setTimeout,以 fullilled 为例。
setTimeout(() => {try {let x = onFulfilled(self.value);ResolutionProcedure(returnedPromise, x, resolve, reject);} catch (e) {reject(e);}}, 0);
完整版
function ResolutionProcedure(promise, x, resolvePromise, rejectPromise) {try {if (promise === x) {return rejectPromise(new TypeError("2.3.1"));}if (x instanceof Promise) {x.then((value) => {return ResolutionProcedure(promise, value, resolvePromise, rejectPromise);},(reason) => {return rejectPromise(reason);});}let called = false;if (x !== null && (typeof x === "object" || typeof x === "function")) {try {let then = x.then;if (typeof then === "function") {then.call(x, (value) => {if (called) return;called = true;return ResolutionProcedure(promise, value, resolvePromise, rejectPromise);}, (reason) => {if (called) return;called = true;return rejectPromise(reason);});} else {return resolvePromise(x);}} catch (e) {if (called) return;called = true;return rejectPromise(e);}} else {return resolvePromise(x);}} catch (e) {return rejectPromise(e);}}function Promise(executor) {let self = this;self.status = "pending";self.value = null;self.onResolveCallbacks = [];self.onRejectCallbacks = [];function resolve(value) {if (self.status === "pending") {self.status = "fulfilled";self.value = value;// executor 异步调用 resolveself.onResolveCallbacks.forEach(cb => cb(self.value));}}function reject(reason) {if (self.status === "pending") {self.status = "rejected";self.value = reason;// executor 异步调用 rejectself.onRejectCallbacks.forEach(cb => cb(self.value));}}try {executor(resolve, reject);} catch (e) {reject(e);}}Promise.prototype.then = function (onFulfilled, onRejected) {let self = this;onFulfilled = typeof onFulfilled === "function" ? onFulfilled : v => v;onRejected = typeof onRejected === "function" ? onRejected : r => {throw r;};let returnedPromise;if (self.status === "fulfilled") {return returnedPromise = new Promise((resolve, reject) => {setTimeout(() => {try {let x = onFulfilled(self.value);ResolutionProcedure(returnedPromise, x, resolve, reject);} catch (e) {reject(e);}}, 0);});}if (self.status === "rejected") {return returnedPromise = new Promise((resolve, reject) => {setTimeout(() => {try {let x = onRejected(self.value);ResolutionProcedure(returnedPromise, x, resolve, reject);} catch (e) {reject(e);}}, 0);});}if (self.status === "pending") {console.log(self.onRejectCallbacks);return returnedPromise = new Promise((resolve, reject) => {self.onResolveCallbacks.push(() => {setTimeout(() => {try {let x = onFulfilled(self.value);ResolutionProcedure(returnedPromise, x, resolve, reject);} catch (e) {reject(e);}}, 0);});self.onRejectCallbacks.push(() => {setTimeout(() => {try {let x = onRejected(self.value);ResolutionProcedure(returnedPromise, x, resolve, reject);} catch (e) {reject(e);}}, 0);});});}};
参考:
