首页 > 解决方案 > 如何将代码从同步和异步类概括为 Javascript/Typescript 中的抽象类

问题描述

假设我有以下课程:

abstract class AbstractFileReader {
  // ???
}

class SyncFileReader extends AbstractFileReader {
  public readFileDecorated(filePath: string): string {
    console.log('Filepath: ');
    console.log(filePath);
    const contents = this.readFileInternal(filePath);
    console.log('Length of file: ');
    console.log(contents.length);
    return contents;
  }
  private readFileInternal(filePath: string): string {
    return fs.readFileSync(filePath, {'encoding': 'utf8'});
  }
}

class AsyncFileReader extends AbstractFileReader {
  // highly redundant code...
  public async readFileDecorated(filePath: string): Promise<string> {
    console.log('Filepath: ');
    console.log(filePath);
    const contents = await this.readFileInternal(filePath);
    console.log('Length of file: ');
    console.log(contents.length);
    return contents;    
  }
  private async readFileInternal(filePath: string): Promise<string> {
    return await fs.promises.readFile(filePath, {'encoding': 'utf8'});
  }
}

const syncFileReader = new SyncFileReader();
const asyncFileReader = new AsyncFileReader();
asyncFileReader.readFileDecorated('./test.txt').then((contents) => {
  console.log(contents);
}).catch((reason) => console.log('abc'));

// The following call should still work without change after the changes in AbstractFileReader.
console.log(syncFileReader.readFileDecorated('./test.txt'));

中的代码readFileDecorated(当然只是一个愚蠢的例子)是高度冗余的,所以我想把它放在一个方法中AbstractFileReader。但是,问题是readFileDecorated同步输入SyncFileReader但异步输入AsyncFileReader

我想出的直截了当的解决方案是在AbstractFileReader. 这会起作用,但是最后一行中的调用必须更改,我不想这样做,因为 aSyncFileReader应该只公开同步语法。

另一种解决方案是使用在调用 之前或之后(分别)调用的方法readFileDecoratedPre(filePath),但是当方法包含多个同步/异步调用时,这不是一个可行的解决方案。readFileDecoratedPost(contents)readFileInternal

标签: javascripttypescriptasynchronousabstract-class

解决方案


您可以使用 Promises 使同步代码异步。您可以创建一个承诺并立即解决它。

这样,SyncFileReader 中的签名与 AsyncFileReader 中的签名相同。

class SyncFileReader extends AbstractFileReader {
  public readFileDecorated(filePath: string): Promise<string> {
    console.log('Filepath: ');
    console.log(filePath);
    const contents = this.readFileInternal(filePath);
    console.log('Length of file: ');
    console.log(contents.length);
    return new Promise((resolve) => resolve(contents));
  }
  private readFileInternal(filePath: string): Promise<string> {
    return new Promise((resolve) => resolve(fs.readFileSync(filePath, {'encoding': 'utf8'})));
  }
}

您还可以检查从方法返回的值是否是 Promise,如果是则等待它。

const promiseContents: string|Promise<string> = this.readFileInternal(filePath);
let contents: string;
if (typeof contents?.then === 'function') {
    contents = await promiseContents
} else {
    contents = promiseContents
}

但这不是最好的解决方案。


推荐阅读