免责声明:我正在努力学习,所以问题可能是微不足道的;任何关于如何更好地做同样的事情的 comments 都是受欢迎的,但我需要理解潜在的概念. 我更像是一名Python程序员,所以async/await比较熟悉,而Promise则是一个相当新的概念.

我有一个简单的Node.js程序,它扫描一个子目录并处理文件名:

const chalk = require('chalk');
const ProgressBar = require('progress');
const fs = require('fs');
const path = require('path');
async function* walk(dir) {
    for await (const d of await fs.promises.opendir(dir)) {
        const entry = path.join(dir, d.name);
        if (d.isDirectory()) yield* await walk(entry);
        else if (d.isFile()) yield entry;
    }
}

async function scan(cb) {
    var docs = [];
    for await (const p of walk('docs')) {
        if (p.endsWith('.md')) {
            console.log(p);
            docs.push(p);
        }
    }
    docs.sort();
    if (cb)
        cb(docs);
}

async function inspect(docs) {
    const bar = new ProgressBar(':bar', { total: docs.length });
    for (f in docs) {
        if (bar.curr === 0) {
            console.log(chalk.green('starting...'));       
        }
        bar.tick();
        // do other work and (possibly) modify `docs` array
        if (bar.complete) {
            console.log(chalk.green('done.'));
        }
    }
    // pass docs to next stage
}

scan(inspect)

由于链将比这长得多(我需要读取文件、根据内容对它们进行排序、构建TOC等),我想修改它以使用类似于以下内容的promise :

scan('/my/dir/to/scan')
    .then(inspect)
    .then(generate, `/path/to/target/file/`)
    .catch(printError)

但我找不到方法(我看到了关于这个问题的几个答案,但我找不到我的问题的真正答案).

推荐答案

我建议,您不应该直接从其他函数调用回调函数.相反,让函数保持简单并返回输出即可.创建一个父函数,使用关键字await逐行调用所有函数,并传递输出.请参阅以下代码:

const chalk = require('chalk');
const ProgressBar = require('progress');
const fs = require('fs');
const path = require('path');
async function* walk(dir) {
    for await (const d of await fs.promises.opendir(dir)) {
        const entry = path.join(dir, d.name);
        if (d.isDirectory()) yield* await walk(entry);
        else if (d.isFile()) yield entry;
    }
}

async function scan() {
    var docs = [];
    for await (const p of walk('docs')) {
        if (p.endsWith('.md')) {
            console.log(p);
            docs.push(p);
        }
    }
    docs.sort();
    return docs;
}

async function inspect(docs) {
    const bar = new ProgressBar(':bar', { total: docs.length });
    for (f in docs) {
        if (bar.curr === 0) {
            console.log(chalk.green('starting...'));       
        }
        bar.tick();
        // do other work and (possibly) modify `docs` array
        if (bar.complete) {
            console.log(chalk.green('done.'));
        }
    }
    // pass docs to next stage
    return docs;
}

async function nextStage(docs){
    // do some stuff and return something
}

async function main(){
    try {
        let docs = await scan();
        docs = await inspect(docs);
        let nextValue = await nextStage(docs);
        // keep adding the calls here. It is more maintainable
    } catch(e){
        // handle the exception here 
    }
}

编辑:要使用Promise执行此操作,您可以参考以下代码.它不是代码的直接转换,但我希望它简化了事情,并且您可以理解如何使用promise :

async function* walk(dir) {
    let files = ['A.txt', 'B.txt', 'A.md', 'B.md', 'c.md'];
    for(file of files){
        yield file;
    }
}

async function scan() {
    var docs = [];
    for await (const p of walk('docs')) {
        if (p.endsWith('.md')) {
            console.log(p);
            docs.push(p);
        }
    }
    docs.sort();
    // return a promise here 
    return new Promise(function (resolve, reject) {
        // Pass the arguments in resolve() 
        resolve(docs);
        // you can also call reject(error) to invoke the catch method
    })
}

async function inspect(docs) {
    // here I am simply renaming the files 
    for(let i=0; i<docs.length; ++i){
        docs[i] = "Renamed"+docs[i];
    }
    console.log("Renamed successfully");
    return docs;
}

async function nextStage(docs){
    // do some stuff and return something
    // lets print the files simply 
    console.log(docs);
    // and return anything if needed 
    return docs.length;
}

scan()
    .then(inspect)
    .then(nextStage)
    .catch((error)=>{
        // handle the error here 
    });


只需注意我们如何从第一个函数返回Promise对象.我们将数据传递给Resolve(),它将作为参数注入到.then()调用中提到的下一个函数中.无论您在哪里抛出任何错误或调用Reject()函数,您都可以跳到.catch()调用.请注意,每个链接的调用都返回一个Promise对象,以便您可以进一步链接它(在调试器中运行它以查看您自己).

Javascript相关问答推荐

使用NgDeliverentOutlet和动态内容投影的Angular 渲染组件

Vue Quill css仅应用于我的第一个Quill Editor组件+如何自定义工具栏

如何通过在提交时工作的函数显示dom元素?

jQuery提交按钮重新加载页面,即使在WordPress中使用preventDefault()

网页自检测外部元素无法加载

使用i18next在React中不重新加载翻译动态数据的问题

WebRTC关闭navigator. getUserMedia正确

手机上的渲染错误文本必须在文本组件中渲染,但在浏览器上没有问题<><>

CheckBox作为Vue3中的一个组件

如何在 cypress 中使用静态嵌套循环

如何在coCos2d-x中更正此错误

是什么导致了这种奇怪的水平间距错误(?)当通过JavaScript将列表项元素追加到无序列表时,是否在按钮之间?

当输入字段无效时,我的应用程序不会返回错误

使用VUE和SCSS的数字滚动动画(&;内容生成)

同一类的所有div';S的模式窗口

自定义确认组件未在vue.js的v菜单内打开

在表单集中保存更改时删除';禁用';

在Vercel中部署Next.js项目时获取`ReferenceError:未定义文档`

重新呈现-react -筛选数据过多

Pevent触发material 用户界面数据网格中的自动保存