我想用ES6语法扩展本机Javascript Promise类,并能够在子类构造函数中调用一些异步函数。基于异步函数结果,必须拒绝或解决承诺。
但是,调用then
函数时会发生两件奇怪的事情:
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)
})

答案 0 :(得分:6)
我发现兑现承诺的最好方法是
class MyPromise extends Promise {
constructor(name) {
// needed for MyPromise.race/all ecc
if(name instanceof Function){
return super(name)
}
super((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
})
this.name = name
}
// you can also use Symbol.species in order to
// return a Promise for then/catch/finally
static get [Symbol.species]() {
return Promise;
}
// Promise overrides his Symbol.toStringTag
get [Symbol.toStringTag]() {
return 'MyPromise';
}
}
new MyPromise('p1')
.then(result => {
console.log('resolved, result: ', result)
})
.catch(err => {
console.error('err: ', err)
})
答案 1 :(得分:5)
推理很简单,但不一定是不言而喻的。
.then()
返回承诺then
,则返回的promise是子类的实例,而不是Promise本身。then
返回的promise,并向其传递一个内部执行函数,该函数记录传递给它的resolve
和reject
参数的值以供以后使用。 then
或onfulfilled
处理程序(稍后)的执行时异步解析或拒绝onrejected
返回的承诺,以查看它们是否返回值(解析返回的then
承诺)或抛出错误(拒绝承诺)。 简而言之then
次调用内部获取并记录对他们返回的承诺的resolve
和reject
函数的引用。
new MyPromise( 'p1')
工作正常,是对子类构造函数的第一次调用。
.then( someFunction)
在someFunction
then
调用列表中记录new MyPromise
(召回then
可多次调用)并尝试通过调用
new MyPromise( (resolve, reject) => ... /* store resolve reject references */
这是对来自then
代码的子类构造函数的第二次调用。期望构造函数(并且确实)同步返回。
从创建返回的承诺返回时,.then
方法进行完整性检查,以查看它以后需要的resolve
和reject
函数是否实际上是函数。它们应该与then
调用中提供的回调一起存储(在列表中)。
在MyPromise
的情况下,他们不是。由then
传递给MyPromise
的执行者甚至没有被调用。因此then
方法代码会抛出类型错误" Promise resolve或reject函数不可调用" - 它无法解决或拒绝它应该返回的承诺。
在创建Promise的子类时,子类构造函数必须将执行函数作为其第一个参数,并使用实际resolve
和reject
函数参数调用执行程序。这是then
方法代码内部要求的。
做一些与MyPromise
复杂的事情,也许检查第一个参数以查看它是否是一个函数并将其作为执行程序调用,如果是,可能是可行的,但不在本答案的范围内!对于显示的代码,编写工厂/库函数可能更简单:
function namedDelay(name, delay=1000, value=1) {
var promise = new Promise( (resolve,reject) => {
setTimeout(() => {
resolve(value)
}, delay)
}
);
promise.name = name;
return promise;
}
namedDelay( 'p1')
.then(result => {
console.log('fulfilled, result: ', result)
})
.catch(err => {
console.error('err: ', err)
})

<小时/> 的; TLDR 强>
Promise的类扩展不是扩展。如果是,则需要实现Promise接口并将执行器函数作为第一个参数。您可以使用工厂函数返回异步解析的Promise(如上所述),或 hack 使用
发布的代码MyPromise.prototype.constructor = Promise
导致.then
返回常规的Promise对象。黑客攻击本身驳斥了类扩展正在发生的想法。