微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何将代码从同步和异步类通用化为Javascript / Typescript

如何解决如何将代码从同步和异步类通用化为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中的方法中。但是,问题在于readFileDecoratedSyncFileReader中是同步的,而在AsyncFileReader中是异步的。

我想到的直接解决方案是使AbstractFileReader中的所有内容保持异步。这可以工作,但是最后一行的调用必须更改,我不想这样做,因为SyncFileReader应该只公开同步语法。

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

解决方法

您可以使用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
}

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

,

我现在寻求以下解决方案:

首先,我创建了一个函数handleValue,如下所示:

function handleValue<T>(sync: boolean,valueOrPromise: T | Promise<T>,callback: (t: T) => void): T | Promise<T> {
  if (sync) {
    const value = valueOrPromise as T;
    callback(value);
    return value;
  } else {
    const promise = valueOrPromise as Promise<T>;
    promise.then(callback);
    return promise;
  }  
}

然后,我按如下方式更改了类(请注意,我对方法签名进行了一些更改):

abstract class AbstractFileReader {
  protected _readFileDecorated(filePath: string,sync: boolean): string | Promise<string> {
    console.log('Filepath: ');
    console.log(filePath);
    const contentsOrPromise = this._readFileInternal(filePath);
    const callback = (contents: string): void => {
      console.log('Length of file: ');
      console.log(contents.length);
    };
    handleValue(sync,contentsOrPromise,callback);
    return contentsOrPromise;
 }

 protected abstract _readFileInternal(filePath: string): string | Promise<string>;
}

class SyncFileReader extends AbstractFileReader {
  public readFileDecorated(filePath: string): string {
    return this._readFileDecorated(filePath,true) as string;
  }
  protected _readFileInternal(filePath: string): string {
    return fs.readFileSync(filePath,{'encoding': 'utf8'});
  }
}

class AsyncFileReader extends AbstractFileReader {
  public async readFileDecorated(filePath: string): Promise<string> {
    return this._readFileDecorated(filePath,false);
  }
  protected async _readFileInternal(filePath: string): Promise<string> {
    return await fs.promises.readFile(filePath,{'encoding': 'utf8'});
  }
}

我承认这有点作弊,因为callback中的_readFileDecorated函数与readFileDecoratedPost(contents)本质上是相同的想法,但是至少它比原始解决方案要好,因为它不再有冗余。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。