手写满足PromiseA+规范源码(上)后续补充
promise对象无法进行链式调用
const promise = new MyPromise((resolve, reject) => {
resolve("hello");
});
promise.then().then().then().then(value => {
return value;
}).then((value) => {
console.log("fulfilled", value)
}, (reason) => {
console.log("rejected", reason)
})
问题分析
- 在promiseA+规范 2.2.7 then must return a promise [3.3].在then方法执行完后必须返回Promise对象,这样就可以进行链式调用。
- 需要对上一个then函数返回的值x进行接收,这边需要对x的类型进行判断和处理,这边封装resolvePromise方法进行处理,这边先假定x为普通值处理,在下面会详细介绍该函数。
- 需要对then中的参数为空时进行值传递。
解决方案
- then方法执行完后需要返回一个promise对象。
- then方法中的参数onFulFilled如果为函数则将其本身赋值,否则就将值往下传递,如果onRejected为函数则赋值本身,否则抛出异常原因;
示例2:
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function" ? onRejected : (reason) => { throw reason };
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED_STATUS) {
try {
let x = onFulfilled(this.value);
resolve(x);
} catch (e) {
reject(e);
}
}
...
});
return promise2;
}
继续完善上述代码
问题背景
-
x返回为promise时,需要对promise进一步处理 ,这边封装resolvePromise方法
调用方式
const promise = new MyPromise((resolve, reject) => {
resolve("hello");
});
promise.then(value => {
return new MyPromise((resolve, reject) => {
resolve(new MyPromise((resolve, reject) => {
resolve(new MyPromise((resolve, reject) => {
resolve('success');
}))
}))
})
}).then((value) => {
console.log("fulfilled", value)
}, (reason) => {
console.log("rejected", reason)
})
如果按示例2的方法,打印的为 fulfilled MyPromise {status: "fulfilled", value: MyPromise, reason: undefined, onFulfillCallbacks: Array(0), onRejectCallbacks: Array(0)},正确应该返回为fulfilled success。
示例三
修改then方法,新增resolvePromise方法,对返回值x进行处理。
resolvePromise方法介绍
首先需要判断x是否为promise对象,如果是则进一步获取promise中的返回值,否则直接resolve即可。
需要判断x和promise是否相等,如果是则会出现循环引用的情况。
判断promise方法,不为null且类型为object或者function,并存在then方法。
由于可能进一步存在嵌套promise,则需要递归进行调用resolvePromise。
循环引用调用方式
const promise = new MyPromise((resolve, reject) => {
resolve("hello");
});
const promise2 = promise.then(value => {
return promise2;
});
promise2.then((value) => {
console.log(value);
})
优化后代码
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
function resolvePromise(promise, x, resolve, reject) {
if (promise === x) {
// 避免循环引用
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
}
let called;
if (x !== null && (["function", "object"].includes(typeof x))) {
// 判断当前x的类型是否为Promise
try {
let then = x.then;
if (typeof then === "function") {
then.call(x, y => {
if (called) return;
called = true;
// y 仍为一个promise 需要递归调用
resolvePromise(promise, 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);
}
}