我想用 ES6 语法扩展原生 Javascript Promise 类,并且能够在子类构造函数中调用一些异步函数。根据异步函数结果,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)
})
最佳答案
推理很简单,但不一定是不言而喻的。
.then()
返回一个 promise then
在 Promise 的子类上调用时,返回的 Promise 是子类的实例,而不是 Promise 本身。 then
返回的 Promise 是通过调用子类构造函数构造的,并传递给它一个记录 resolve
值的内部执行器函数。和 reject
传递给它的参数以供以后使用。 then
返回的 promise 在监视 onfulfilled
的执行时异步或 onrejected
处理程序(稍后)查看它们是否返回值(解析 then
返回的 promise )或抛出错误(拒绝 promise )。 总之
then
内部调用获取并记录对 resolve
的引用和 reject
它们返回的 promise 的函数。所以关于这个问题,
new MyPromise( 'p1')
工作正常,是对子类构造函数的第一次调用。.then( someFunction)
记录 someFunction
在 then
的列表中调用 new MyPromise
的电话(记忆 then
可以多次调用)并尝试通过调用来创建返回 promise new MyPromise( (resolve, reject) => ... /* store resolve reject references */
这是来自 then
的对子类构造函数的第二次调用。代码。构造函数应该(并且确实)同步返回。从创建返回 promise 返回时,
.then
方法进行完整性检查以查看 resolve
和 reject
它需要供以后使用的函数实际上是函数。它们应该与 then
中提供的回调一起存储(在列表中)。称呼。在
MyPromise
的情况下他们不是。执行人通过then
, 至 MyPromise
, 甚至没有被调用。所以then
方法代码抛出一个类型错误“Promise resolve or reject function is not callable”——它没有办法解决或拒绝它应该返回的 Promise。在创建 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 接口(interface)并将执行器函数作为第一个参数。您可以使用工厂函数返回异步解析的 Promise(如上),或 黑客 发布的代码与
MyPromise.prototype.constructor = Promise
导致 .then
返回一个常规的 Promise 对象。 hack 本身驳斥了正在发生类扩展的想法。promise 扩展示例
以下示例显示了一个基本的 Promise 扩展,它添加了提供给构造函数的属性。注意:
Symbol.toString
getter仅影响将实例转换为字符串的输出。在测试的浏览器控制台上记录实例对象时,它不会将“Promise”更改为“MyPromise”。class MyPromise extends Promise {
constructor(exec, props) {
if( typeof exec != "function") {
throw TypeError( "new MyPromise(executor, props): an executor function is required");
}
super((resolve, reject) => exec(resolve,reject));
if( props) {
Object.assign( this, props);
}
}
get [Symbol.toStringTag]() {
return 'MyPromise';
}
}
// Test the extension:
const p1 = new MyPromise( (resolve, reject) =>
resolve(42),
{id: "p1", bark: ()=>console.log("woof") });
console.log( "p1 is a %s object", p1.constructor.name);
console.log( "p1.toString() = %s", p1.toString());
console.log( "p1.id = '%s'", p1.id);
console.log( "p1 says:"); p1.bark();
const pThen = p1.then(data=>data);
console.log( "p1.then() returns a %s object", pThen.constructor.name);
let pAll = MyPromise.all([Promise.resolve(39)]);
console.log( "MyPromise.all returns a %s object", pAll.constructor.name);
try { new MyPromise(); }
catch(err) {
console.log( "new MyPromise() threw: '%s'", err.message);
}
关于javascript - 扩展 Javascript promise 并在构造函数中解决或拒绝它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48158730/