Tuesday, 7 July 2026

Spot The Bug: It's a Bug! It's a Plane!

Well hello, readers! Time for some more Spot The Bug!

Go away or be
squashed, bugs!


This episode revolved around NodeJS. My code was supposed to read a CSV file and display the contents in table format. The most basic shit ever. Somehow I managed to screw it up!

This was the script that would be executed. Basically, I would load the file tbl.csv, from the file system, and parse it as CSV text. And make sure each row got pushed into an array. Then after that, a HTML table would be created from the CSV rows, and inserted into the view.

app.js
var express = require("express");

var app = express();

var handlebars = require("express-handlebars").create({defaultLayout:"main"});
app.engine("handlebars", handlebars.engine);

app.set("view engine", "handlebars");
app.set("port", process.env.PORT || 3000);

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.use(express.static("assets"));

const fs = require("fs");
const csv = require("csv-parser");

let csvContent = [];

function loadFileCSV(filePath) {
   return new Promise((resolve, reject) => {
      const resultsCSV = [];

      fs.createReadStream(filePath)
      .pipe(csv())
      .on("data", (row) => {
         resultsCSV.push(row);
      })
      .on("end", () => resolve(resultsCSV))
      .on("error", (err) => reject(err));
   });
}

async function loadTableCSV() {
   try {
     csvContent = await loadFileCSV("assets/csv/tbl.csv");
   } catch (err) {
     throw new Error("Error reading CSV.");
     console.error("Error reading CSV:", err);
   }
}  

app.get("/superman", (req, res)=> {
  loadTableCSV();
  
  let csvTable = "<table><tr><td>Title</t><td>Year</t><td>Actor</t></tr>";

  for (let i = 0; i < csvContent.length; i++)
  {
    csvTable += "<tr><td>" + csvContent[i].Title + "</t><td>" + csvContent[i].Year + "</t><td>" + csvContent[i].Actor + "</t></tr>";
  }  

  csvTable += "</table>";

  res.render("superman", { table: csvTable });
});

app.use((req, res, next)=> {
  res.status(404);
  res.render("404");
});

app.use((err, req, res, next)=> {
  res.status(500);
  res.render("500", { errorMessage: err.code });
});

app.listen(app.get("port"), ()=> {

});


This was the view.

views/layouts/main.handlebars
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Superman</title>

    <link rel="stylesheet" type="text/css" href="css/styles.css">
  </head>
  <body>
    <h1>SUPERMAN DATA</h1>
    <div class="content">
      {{{ body }}}  
    </div>    
  </body>
</html>


views/superman.handlebars
<div>
{{{ table }}}
</div>

And this was the data.

assets/csv/tbl.csv
Title,Year,Actor
Superman/Atom Man vs. Superman,1948-1950,Kirk Alyn
Superman and the Mole Men/Adventures of Superman,1951-1958,George Reeves
The Adventures of Superboy (Pilot),1961,Johnny Rockwell
It's a Bird... It's a Plane... It's Superman,1975,David Wilson
Superman I-IV,1978-1987,Christopher Reeve
Superboy (TV Series),1988-1992,J.H. Newton/G. Christopher
Lois & Clark: The New Adventures of Superman,1993-1997,Dean Cain
Smallville,2001-2011,Tom Welling
Superman Returns,2006,Brandon Routh
Man of Steel/BvS/Justice League,2013-2017,Henry Cavill
Supergirl/Arrowverse/Superman & Lois,2016-2024,Tyler Hoechlin
Titans,2019-2023,Joshua Orpin
The Flash,2023,Nicolas Cage
Superman,2025,David Corenswet


What Went Wrong

So... wow. Totally nothing. No error, even. Why?



Why It Went Wrong

Notice that loadTableCSV() is an async function. Which means any call to loadTableCSV() better be async as well, or nothing will be returned. What happened was that I called loadTableCSV() and then went on to use csvContent without realizing that its value was as I initialized - an empty array. Because I didn't wait for the CSV data to load before using csvContent!
app.get("/superman", (req, res)=> {
  loadTableCSV();


Eventually, if I waited long enough, the data might show. But that would be scant consolation and something was still obviously wrong.

How I Fixed It

As it turned out, that was all that was needed. Change the callback signature to an async one, and the function call to loadTableCSV(), to an await function call.
app.get("/superman", async(req, res)=> {
  await loadTableCSV();


And the Superman table appeared!


Moral of the Story

Async is a tricky business. JavaScript, being async, is a tricky business by extension. And when you have NodeJS which is JavaScript in the front and back, it's a doubly tricky business.

Up up and away,
T___T

No comments:

Post a Comment