【问题标题】:How to refactor simple for-await-of loop?如何重构简单的 for-await-of 循​​环?
【发布时间】:2019-02-19 23:43:27
【问题描述】:

我正在使用一些新的 JavaScript 功能,例如 async/await 和生成器。我有函数readPages 签名

async function* readPages(....): AsyncIterableIterator<string> {}

我想用一些分隔符连接这个函数的结果。这是我现在的做法

let array = new Array<string>();

for await (const page of readPages(...))
    array.push(page);

let result = array.join(pagesDelimiter);

我认为这很冗长。能不能做得更好?

这里是完整的代码供参考

import * as fs from 'fs';
import { PDFJSStatic, PDFDocumentProxy } from 'pdfjs-dist';
const PDFJS: PDFJSStatic = require('pdfjs-dist');
PDFJS.disableWorker = true;

async function* readPages(doc: PDFDocumentProxy, wordsDelimiter = '\t'): AsyncIterableIterator<string> {
    for (let i = 1; i <= doc.numPages; i++) {
        const page = await doc.getPage(i);
        const textContent = await page.getTextContent();
        yield textContent.items.map(item => item.str).join(wordsDelimiter);
    }
}

async function pdfToText(filename: string, pagesDelimiter = '\n', wordsDelimiter = '\t') {
    const data = new Uint8Array(fs.readFileSync(filename));
    const doc = await PDFJS.getDocument(data);

    const array = new Array<string>();

    for await (const page of readPages(doc, wordsDelimiter))
        array.push(page);

    return array.join(pagesDelimiter);
}

pdfToText('input.pdf').then(console.log);

【问题讨论】:

  • 4 行(1 个声明,一个循环,带有数组推送,最后一个用于连接)是......冗长?我看不到代码的重复,我看不到一个臭虫球或一盘装满难以理解的纠缠意大利面。我不明白你到底想“重构”什么?您打算改进什么?
  • 类似readPages(...).join(delimiter) :-)
  • 所以你想要一个更“功能性”的代码而不是一个普通的循环。它让我不由自主地想到 rxjs Observables。您最终可能会得到更多行,但使用的是功能性方法。
  • 我只是认为,这是避免 for 循环的好选择。如果写 ['a', 'b', 'c'].join('_') 比 for 循环更可取,这也应该是(如果存在解决方案)。 RxJS 不能使用 Promises 操作(或者我错了),它是另一个库。我正在寻找原生 JavaScript 解决方案。
  • RxJS 可以使用 promise (Observable.fromPromise() ;) ) 运行。它也可以与 Iterable (Observable.from) 一起使用。不过,现在不知道如何混合两者。

标签: typescript async-await async-iterator


【解决方案1】:

好的,我正在更多地使用该代码,我认为目前无法比使用for-await-of 循环更好地处理此任务。 但是,您可以将该循环隐藏在原型函数后面...

declare global {
    interface AsyncIterableIterator<T> {
        toPromise(): Promise<T[]>;
    }
}

(async function* (): any {})().constructor.prototype.toPromise = async function<T>(this: AsyncIterableIterator<T>): Promise<T[]> {
    let result = new Array<T>();

    for await (const item of this)
        result.push(item);

    return result;
};

所以我的代码

const array = new Array<string>();

for await (const page of readPages(...))
    array.push(page);

const result = array.join(pagesDelimiter);

变成

const array = await readPages(...).toPromise();
const result = array.join(pagesDelimiter);

是的,我知道,原型设计是有问题的。但有趣的是,如何设计异步迭代器的原型 :-)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-20
    • 2020-07-10
    • 2020-01-04
    • 2021-08-15
    • 2018-08-20
    • 2021-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多