扩展 JavaScript Promise 时出错

Error when extending JavaScript Promise

本文关键字:出错 Promise JavaScript 扩展      更新时间:2023-09-26

我有一个接受回调的Worker类,但我想通过使其成为Promise来删除回调,所以我可以做new Worker(stuff, otherStuff).then(function() { ... });

为此,我使用了extends关键字。

起初,我在this.a = a;作业中遇到了ReferenceError: this is not defined错误,但我发现那是因为我不得不打电话给super();

现在,它在this.resolve({output: 'ok'});行处给出了TypeError: this.resolve is not a function,所以我试图强行添加this.resolvethis.reject函数,但错误不会消失。

这是(高度简化的(代码:

class Worker extends Promise {
    constructor(a, b) {
        super((resolve, reject) => {
            console.log('inside super');
            this.resolve = resolve;
            this.reject = reject;
        });
        console.log('start constructing');
        this.a = a;
        this.b = b;
        console.log('A: ' + JSON.stringify(a));
        console.log('B: ' + JSON.stringify(b));
        this.doStuff();
        if (!this.status) {
            this.resolve({output: 'ok'});
        } else {
            this.reject('There was an error');
        }
    }
    doStuff() {}
}
let a = {x: 1};
let b = {z: 2};
console.log('before creation');
let w = new Worker(a, b);
console.log('after creation');
w.then(function() {
    console.log('done');
});

我正在使用节点 6.1.0,它似乎支持Promise子类......我做错了什么?

最佳做法是避免扩展基元类,因为它们会发生变化。扩展它们会使您自己的类受到浏览器/引擎的怜悯。

当你尝试扩展 Promise 类时,this不会在构造函数中定义,因为现在大多数引擎都不支持子类化 Promise。

此外,工人不是承诺。工人应该工作并做出承诺。

解决方案是使用包装器或工厂模式,而不是继承。

例如,您可以在 Worker 类中定义一个 getter promise,该 getter 将创建一个新的 Promise 实例并返回它。

function serializeError(error({return{message:error.message||",名称:错误.名称||",堆栈:错误.堆栈||"}}class NativeResolver{constructor(({this.resolve;this.reject;this.promise=new Promise(((resolve,reject(=>{this.resolve=resolve;this.reject=reject}((}}function assertCast(condition({if(!condition({throw new Error("Failed assertion"(}return condition}const ReservedMessageTypes={RESPONSE_TYPE:">response",ERROR_TYPE:">error"};function isGenerated Message(messageType({return messageType.substr(0,3(===">"}function throwIfReserved(messageType({if(isGeneratedMessage(messageType(({throw new Error( Unexpected reserved message type: '${messageType}' (}}class MessagePipe{constructor(targetOrigin,target,rethrowErrors=true({if(!target({const frame=document.querySelector( iframe[src^='${targetOrigin}'] (;if(!frame||!frame.contentWindow({throw new Error("T无法定位目标内容窗口"(}target=assertCast(frame.contentWindow(}this.target=target;this.targetOrigin=targetOrigin;this.rethrowErrors=rethrowErrors;this.logClientError=object=>console.error(JSON.stringify(object((;this.messageHandlers=new Map;this.pendingMessages_=new Map;this.nextMessageId_=0;this.messageListener_=m=>this.receiveMessage_(m(;console.assert(this.target_!==window,"target !== window"(;window.addEventListener("message",this.messageListener_(}registerHandler(messageType,handler({throwIfReserved(messageType(;if(this.messageHandlers_.has(messageType(({throw new Error( A handler already exists for ${messageType} (}this.messageHandlers_.set(messageType,handler(}async sendMessage(messageType,message={}({try{return await this.sendMessageImpl(messageType,message(}catch(errorResponse({const error=new Error( ${messageType}: ${errorResponse.message} (;error.name=errorResponse.name||"Unknown Error";error.stack+= 'nError from ${this.targetOrigin_}'n${errorResponse.stack} ;throw error}}async sendMessageImpl(messageType,message={}({throwIfReserved(messageType(;const messageId=this.nextMessageId_++;const resolver=new NativeResolver;this.pendingMessages_.set(messageId,resolver(;this.postToTarget_(messageType,message,messageId(;return resolver.promise}detach(({window.removeEventListener("message",this.messageListener_(}handleMessageResponse_(messageType,message,messageId({const{RESPONSE_TYPE:RESPONSE_TYPE,ERROR_TYPE:ERROR_TYPE}=ReservedMessageTypes;const resolver=this.pendingMessages_.get(messageId(;if(messageType===RESPONSE_TYPE({resolver.resolve(message(}else if(messageType===ERROR_TYPE({this.logClientError(message(;resolver.reject(message(}else{console.error( Response for message ${messageId} received with invalid message type ${messageType} (}this.pendingMessages_.delete(messageId(}async callHandlerForMessageType_(messageType,message,messageId({const{RESPONSE_TYPE:RESPONSE_TYPE,ERROR_TYPE:ERROR_TYPE}=ReservedMessageTypes;let response;let error=null;let sawError=false;try{response=await this.messageHandlers_.get(messageType((message(}catch(err({sawError=true;error=err;response=serializeError(err(}this.postToTarget_(sawError?ERROR_TYPE:RESPONSE_TYPE,response,messageId(;if(sawError&&this.rethrowErrors({this.logClientError(error(;throw error}}receiveMessage_(event({const e=event;if(typeof e.data!=="object"||!数据||typeof e.data.type!=="string"({return}const{messageId:messageId,type:type,message:message}=e.data;const{ERROR_TYPE:ERROR_TYPE}=ReservedMessageTypes;if(e.origin!==this.targetOrigin_&&this.targetOrigin_!=="*"({return}if(isGenerated Message(type(&&this.pendingMessages_.has(messageId(({this.handleMessageResponse_(type,message,messageId(;return}if(isGeneratedMessage(type(({console.error( Response with type ${type} for unknown message received. (;return}if(!this.messageHandlers_.has(type(({const error=new Error( No handler registered for message type '${type}' (;const errorResponse=serializeError(error(;this.postToTarget_(ERROR_TYPE,errorResponse,messageId(;return}this.callHandlerForMessageType_(type,message,messageId(}postToTarget_(messageType,message,messageId({const messageWrapper={messageId:messageId,type:messageType,message:message||{}};this.target_.postMessage(messageWrapper,this.targetOrigin_(}}