避免显式传递"this"上下文的方法?



在开发新产品时,我创建了一个后端和前端项目。对于前端,我使用带有Typescript的Angular框架。以下是一个问题,因为我是一个新的语言(几天前(。我的问题是关于回调以及如何避免使用"this"上下文的显式传递。我已经阅读了一些资源,我将把它们链接起来。

下面我将为HttpClient实现一个包装器。快速版本是使用遵循插件架构(由角度路由支持(的模式进行流控制。最好用一个使用观察者和订阅者的中央委托来广播错误,比如401,以实现优雅的重新进入(在我看来(-我们不会讨论这一点,但提到上下文可能会有所帮助。

以下是我的代码的基本内容:包装=>

export class WebService {
constructor(private httpClient: HttpClient,
private exceptionService: ExceptionService<Exception>) { }
public post<T>(url: string, dataToPost: any, callBack: (responseData: T) => 
void, callBackInstance: any): void {
this.httpClient.post<T>(url, dataToPost).subscribe(
(data: T) =>  {
callBack.call(callBackInstance, data);
},
(error: HttpErrorResponse) => {
this.exceptionService.notify(error);
}
);

现在,我可以使用.call((为回调显式地管理"this"上下文。我不介意在您的任何建议中使用它-但是,查看签名,您会发现该方法要求您传入所需的"this"语境(callbackInstance(。这将一些责任推到了我不想要的方法的调用者身上。对我来说,一个类非常像一个以"this"作为初始位移的数组——因为我正在传递回调的方法;真的没有办法检查这种方法来得出合适的"这个"吗?大致如下:callbackInstance=callback.getRelativeContext((;callBack.call(callBackInstance,data(;这将消除额外的参数,使我的团队使用该方法时不太容易出错。

欢迎链接到资源,但如果可能的话,请尽量将其缩小到相关部分。

链接:

用于更新"此"上下文

参数回调

编辑:从接受的答案中,我得出并放入测试用例:

const simpleCallback = (response) => {holder.setValue(response); };
service.post<LoginToken>(Service.LOGIN_URL, '', simpleCallback);

如果需要将上下文传递给回调,那么回调本身将依赖于该上下文:

function explicitContext(callback, context) {
const arg = 1;
callback.call(context, arg);
}
function implicitContext(callback) {
const arg = 1;
const someCleverContext = {importantVal: 42, importantFunc: () => {}};
callback.call(someCleverContext, arg);
}

如果我们需要实际访问回调中的上下文,请考虑其用法:

function explicitUsage() {
const someCleverContext = {importantVal: 42, importantFunc: () => {}};
const callback = function(arg) {this.importantFunc(arg);}
explicitContext(callback, someCleverContext);
}
function implicitUsage() {
const callback = function(arg) {this.importantFunc(arg);}
implicitContext(callback);
}

在这两种情况下,我们实际上都在泄露上下文的细节,并迫使消费者承担一些责任!现在,如果我们真的需要传递上下文,没有什么神奇的方法可以绕过它。好消息是,我们可能一开始就不需要传递上下文。

export class WebService {
constructor(
private httpClient: HttpClient,
private exceptionService: ExceptionService<Exception>)
{ }
public post<T>(url: string, dataToPost: any, callBack: (responseData: T) => void): void {
this.httpClient.post<T>(url, dataToPost).subscribe(
(data: T) => {
callBack(data);
},
(error: HttpErrorResponse) => {
this.exceptionService.notify(error);
},
);
}
}

通过这种方式,我们可以让客户端代码只关心responseData,如果他们需要一些巧妙的上下文,他们可以自由地自己绑定:

function usage() {
let webService: WebService;
const simpleCallback = (response) => {console.log(response);} // can inline too
webService.post('/api', {data: 1}, simpleCallback);
const cleverContextCallback = function(response) {this.cleverLog(response)};
const cleverContext = {cleverLog: (data) => console.log(data)};
const boundCallback = cleverContextCallback.bind(cleverContext);
webService.post('/api', {data: 1}, boundCallback );
}

说了这么多,我绝对建议您只返回您服务中的可观察到的内容。

export class WebService {
constructor(
private httpClient: HttpClient,
private exceptionService: ExceptionService<Exception>)
{ }
public post<T>(url: string, dataToPost: any, callBack: (responseData: T) => void): Observable<T> {
const observable = this.httpClient.post<T>(url, dataToPost);
// Note that httpClient.post automatically completes.
// If we were using some other library and we would want to close the observable ourselves,
// you could close the observable yourself here after one result:
if ('we need to close observable ourselves after a result') {
return observable.pipe(take(1));
}
if ('we need to handle errors') {
return observable.pipe(
catchError(error => {
this.exceptionService.notify(error);
if ('We can fallback') {
return of('Fallback Value');
} else {
throw new Error('OOPS');
}
}),
);
}
return observable;
}
}

处理服务内部的错误、关闭和其他杂务会让服务的使用者专注于响应中的数据。

最新更新