..

Javascript notes part 2

Ok, after callback. I also have to remind myself about Promise and async await.

Aysnchronous

When I see asynchronous, I think of something can be done while another thing is doing something else. For example, I need eggs before I could bake some pancakes. Instead of waiting for the eggs, I can start doing something else like prepare the kitchen and the other ingredients. This way waiting for the eggs doesn’t block me in doing something else that help me accomplish baking some pancakes.

Promise

Promise is an object which is an improvement on expressing asynchronous code. We can do asynchronous code with callbacks, but with Promise objects, we can avoid too many nested callbacks. Also, Promise is more easier to understand when reading code, so Promise objects are easier to debug than callbacks.

Here is an example code I got from eloquentjavascript.

class Timeout extends Error {}

function request(nest, target, type, content) {
  return new Promise((resolve, reject) => {
    let done = false;
    function attempt(n) {
      nest.send(target, type, content, (failed, value) => {
        done = true;
        if (failed) reject(failed);
        else resolve(value);
      });
      setTimeout(() => {
        if (done) return;
        else if (n < 3) attempt(n + 1);
        else reject(new Timeout("Timed out"));
      }, 250);
    }
    attempt(1);
  });
}

This is how the request function that returns a Promise might be used:

request({send: ()=>{}}, 'target', 'type', 'content')
    .then((value) => {
        console.log(value)
    })
    .catch((err) => {
        console.error(err)
    })

Async and Await

As you can see on the code above. We can potentially have to many chains of then and catch on a code. We can improve that by using async and await.

await is used to define a function that contains await. await is used to run a function that expects to return a Promise object.

const statPair = async (filename) => {
    const stats = await fs.statAsync(filename)
    return { filename, stats }
}

const lineCount = async (filename) => {
    const data = await fs.readFileAsync(filename, 'utf-8')
    return {
        filename,
        lines: data.split('\n').length - 1
    }
}

const main = async (srcDir) => {
    const files = await glob(`${srcDir}/**/*.*`)
    const pairs = await Promise.all(
        files.map(async filename => await statPair(filename))
    )
    const filtered = pairs
        .filter(pair => pair.stats.isFile())
        .map(pair => pair.filename)
    const counts = await Promise.all(
        filtered.map(async name => await lineCount(name))
    )
    counts.forEach(
        ({filename, lines}) => console.log(`${lines}: ${filename}`)
    )
}

const srcDir = process.argv[2]
main(srcDir)