skip to Main Content

Disclaimer: I am trying to learn, so question may be (an probably is) trivial; any comment on better ways to do the same are welcome, but I need to understand underlying concepts.
I am more of a python programmer, so async/await is somewhat familiar, while Promise is a rather new concept.

I have a simple Node.js program scanning a subdirectory and doing stuff with filenames:

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)

Since the chain will be much longer than this (I need to read files, order them according to content, build a TOC, etc.) I thought to modify it to use promises to resemble something like:

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

But I couldn’t find a way to do it (I saw several answers on the subject, but I couldn’t find a real answer to my question).

2

Answers


  1. What do you want to do? What isnt working?

    At a quick glance, this seems like a fine use of await. The await keyword halts at that line until the promise resolves or rejects. The then() doesnt halt the program, but runs the callback whenever the promise resolves. The catch() does the same, but for the reject case of the promise.

    Perhaps your program exits without awaiting the scan()… call? Just put await in front of it, if your Node.js version supports "top level await". Otherwise there is another trick to do the same.

    Login or Signup to reply.
  2. I would suggest, you should not call the callback functions directly from other functions. Instead, keep your functions simple and return the output. Create a parent function and call all the functions line by line using await keyword and pass the output. Refer below code:

    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 
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search