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 = this
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
onRejected = 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。
// pending
self.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);
}
});
// fullilled
try {
let x = onFulfilled(self.value);
ResolutionProcedure(returnedPromise, x, resolve, reject);
} catch (e) {
reject(e);
}
// rejected
try {
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 异步调用 resolve
self.onResolveCallbacks.forEach(cb => cb(self.value));
}
}
function reject(reason) {
if (self.status === "pending") {
self.status = "rejected";
self.value = reason;
// executor 异步调用 reject
self.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);
});
});
}
};
参考: