一种避免显式传递“ this”上下文的方法?

时间:2018-11-26 08:21:24

标签: angular typescript

在开发新产品时,我创建了一个后端和前端项目。对于前端,我将Angular框架与Typescript一起使用。以下是我刚接触该语言的问题(刚出生几天)。我的问题是关于回调以及如何避免使用“ 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”作为初始位移的数组-因为我传入了回调方法;真的没有办法检查该方法以得出适当的“ this”吗?类似于以下内容:     callbackInstance = callback.getRelativeContext();     callBack.call(callBackInstance,data); 这样可以消除多余的参数,从而使该方法更易于我的团队使用。

欢迎使用资源链接-但如果可能,请尝试将其范围缩小到相关部分。

链接:

For updating the "this" context

Parameter callbacks

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

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

1 个答案:

答案 0 :(得分:0)

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

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;
    }
}

处理错误,关闭服务以及其他内部琐事会使服务的使用者将精力集中在响应中的数据上。