Force instance of Database using all() in serial to update global variable

41 Views Asked by At

I am learning sqlite3 in Node.js and having problem with following code

var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('first.db');

console.log("in the program");
var x = [];
console.log("x = ", x);

console.log("db.all()");
db.all("SELECT * FROM coords",
  function(err, rows) {
    console.log("\nin db.all()");
    for(var row of rows) {
      x.push(row.x);
      console.log(x);
    }
  }
);

db.close();

console.log("x = ", x);

where the output is

> node dball.js
in the program
x =  []
db.all()
x =  []

in db.all()
[ 1 ]
[ 1, 5 ]
[ 1, 5, 9 ]

It seems that all lines outside db.all() are executed first than the others inside it, so that array of x seems not changed, since it is printed before it is updated.

Is there any way force all lines are executed in serial instead sort of concurrent? I believe I am missing the concept of concurrency here but not know how to do.

Thank's for any help.

1

There are 1 best solutions below

3
On BEST ANSWER

db.all is a function that takes 2 inputs: the query as a string and a callback function which will be called later when the database managed to run the query and have the results (or an error) ready to report back to you. I suggest you read more about the nature of asynchronous code in JavaScript: callbacks, promises, async/await, etc. Also, we no longer use var to declare variables.

That being said, what you can actually do is to "promisify" db.all function and then use async/await to make it look synchronous (it will still be async code).

const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database('first.db');

function getData(query) {
  // promisifying
  return new Promise((resolve, reject) => {
    db.all(query, (err, rows) => {
      if (err) {
        reject(err);
        return;
      }
      
      resolve(rows);
    }); // db.all
  }); // new Promise
} // getData

// main is needed because some JS engines don't allow top level "await"
// so I am playing safe here
async function main() {
  console.log("in the program");
  const x = [];
  console.log("x = ", x);

  console.log("db.all()");
 
  try {
    // the nice thing is that you don't even need `x` now because
    // you can just do something with `rows`
    const rows = await getData("SELECT * FROM coords");
    for(var row of rows) {
      x.push(row.x);
      console.log(x);
    }
  } catch (err) {
    // do something in case of error
  } finally {
    // this is always executed regardless of error or not
    // so it is a good place to close the database
    db.close();
  }

  console.log("x = ", x);
}

// make sure to call main
main();