我想用ES6语法扩展本机Javascript Promise类,并能够在子类构造函数中调用一些异步函数 . 基于异步函数结果,必须拒绝或解析承诺 .
但是,调用 then
函数时会发生两件奇怪的事情:
-
子类构造函数执行两次
-
“未捕获TypeError:Promise解析或拒绝函数不可调用”抛出错误
class MyPromise extends Promise {
constructor(name) {
super((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
})
this.name = name
}
}
new MyPromise('p1')
.then(result => {
console.log('resolved, result: ', result)
})
.catch(err => {
console.error('err: ', err)
})
1 回答
推理很简单,但不一定是不言而喻的 .
.then()
返回一个承诺如果在Promise的子类上调用
then
,则返回的promise是子类的实例,而不是Promise本身 .then
返回的promise是通过调用子类构造函数构造的,并向它传递一个内部执行函数,该函数记录传递给它的resolve
和reject
参数的值以供以后使用 ."later use"涵盖在监视
onfulfilled
或onrejected
处理程序(稍后)的执行时异步解析或拒绝then
返回的承诺,以查看它们是否返回值(解析then
返回的承诺)或抛出错误(拒绝承诺) .简而言之,
then
调用内部获取并记录对它们返回的promise的resolve
和reject
函数的引用 .关于这个问题,
工作正常,是第一次调用子类构造函数 .
在
new MyPromise
的then
调用列表中记录someFunction
(可以多次调用then
)并尝试通过调用创建返回承诺这是来自
then
代码的子类构造函数的第二次调用 . 期望构造函数(并且确实)同步返回 .在从创建返回的promise返回时,
.then
方法进行完整性检查,以查看它以后需要的resolve
和reject
函数是否实际上是函数 . 它们应该与then
调用中提供的回调一起存储(在列表中) .在
MyPromise
的情况下,他们不是 . 由then
传递给MyPromise
的执行程序甚至不被调用 . 所以then
方法代码抛出一个类型错误"Promise resolve or reject function is not callable" - 它无法解析或拒绝它应该返回的promise .在创建Promise的子类时,子类构造函数必须将executor函数作为其第一个参数,并使用真正的
resolve
和reject
函数参数调用执行程序 . 这是then
方法代码内部要求的 .做一些与
MyPromise
错综复杂的事情,或许检查第一个参数以查看它是否是一个函数并将其作为执行程序调用(如果是),这可能是可行的,但不在本答案的范围内!对于显示的代码,编写工厂/库函数可能更简单:;TLDR
Promise的类扩展不是扩展 . 如果是,则需要实现Promise接口并将 Actuator 函数作为第一个参数 . 您可以使用工厂函数返回异步解析的Promise(如上所述),或 hack 已发布的代码
这会导致
.then
返回一个常规的Promise对象 . 黑客本身驳斥了类扩展正在发生的想法 .