1

我正在使用一些新的 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 回答 1

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

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

于 2018-09-15T20:15:40.503 回答