Node.js blocking versus non-blocking

  Copyright
Resources
Blocking
import * as file_system from 'fs';
import * as path from 'path';

const Blocking = () => {
    // Blocks here until 'Data.txt' file is read:
    const data: Buffer = file_system.readFileSync(path.resolve(__dirname, '..') + "/Data.txt");
    console.log(data.toLocaleString()); // 'Data' is displayed...
    console.info("This text appears *AFTER* 'Data'");
}

export default Blocking;
Non-blocking
import * as file_system from 'fs';
import * as path from 'path';

const Non_blocking = () => {
    file_system.readFile((path.resolve(__dirname, '..') + "/Data.txt"), (error, data) => {
        if (error) throw error;
        console.log(data.toLocaleString()); // 'Data' is displayed...
    });
    console.info("This text appears *BEFORE* 'Data'");
}

export default Non_blocking;
Main program
import Blocking from './Blocking';
import Non_blocking from './Non_blocking';

(function Main() {
    console.clear();
    console.info("Executable file: " + __filename + "\n");
    Blocking();
    setTimeout((duration) => {
        console.info(duration + " elapsed...");
        Non_blocking();
    }, 2500, '2.5 sec.');
})();

Exercise

Events

Predefined event types identified by names like 'close', 'error', 'finish'… are available from (typed) resources like standard input, standard output….

(function Keyboard(information) {
    console.info(`${information}`);

    const output_stream = fs.createWriteStream(
        path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') + "/Keyboard.txt");
    output_stream.on('error', (error) => console.info(`error: ${error.message}`));

    const input_stream = readline.createInterface({ // 'import readline from 'node:readline';'
        input: process.stdin,
        output: process.stdout,
        prompt: "Enter a sentence: "
    });
    input_stream.prompt();
    input_stream.on('line', (line) => {
        switch (line.trim()) {
            case 'exit':
                input_stream.close();
                break;
            default:
                output_stream.write(line + '\n');
                input_stream.prompt(); // Next sentence...
        }
    }).on('close', () => {
        output_stream.end();
        output_stream.on('finish', () => console.info("Sentences have been written to 'Keyboard.txt'..."));
        // Program stop (without error) is queued:
        setTimeout(() => process.exit(0));
    });
})("'Keyboard' app. started...");
Custom events

Node.js offers a native event model, which in particular allows custom event emission and reception. An advanced event model is based on the RxJS library.

Event reception

// import {channel} from "./Input"; // Compilation...
import {channel} from "./Input.js"; // Execution...

channel.on('html', (html) => console.info("***\n" + html));

Event emission

import events from "node:events";
import fs from "node:fs";
import path from "node:path";
import {fileURLToPath} from "node:url";

export const channel = new events.EventEmitter();

(function Input(information) {
    console.info(`${information}`);
    const __dirname = path.dirname(fileURLToPath(import.meta.url));
    const input_stream: fs.ReadStream = fs.createReadStream(path.resolve(__dirname, '..') + "/index.html", 'utf8');
    input_stream.on('error', (error) => console.info(`error: ${error.message}`));
    input_stream.on('data', (html) => channel.emit('html', html));
})("'Events' app. started...");