0

I'm awful with Async code in Javascript and have been stuck on something for a while now.

I'm working with WebSql and just going through database initialization steps but one of the loops is not executing in the way I expect it to.

$(document).ready(function() {
    initdatabase();
});

function initdatabase() {

    var db = window.openDatabase("nothing", "1.0", "nothing", 2 * 1024 * 1024);

    db.transaction(function(trans) {

        trans.executeSql("CREATE TABLE", [], function(trans, result) {
            // success
            defaultdata(db);
        }, function(error) {
            // failed
        });

    });

}

function defaultdata(db) {

    db.transaction(function(trans) {

        var lo_data = [
        {code:"CODE01", desc:"Code 01 Desc"},
        {code:"CODE02", desc:"Code 02 Desc"},
        {code:"CODE03", desc:"Code 03 Desc"}
        ];

        for(i = 0; i < lo_data.length; i++) {

            trans.executeSql("INSERT", [lo_data[i].code, lo_data[i].desc], function(trans, result) {
                // success
                console.log("INS : " + i);
            }, function(error) {
                // failed
            });

        }

        console.log("END");

    });

}

But the log to indicate the end is executing before the for loop has finished. If I try validate that the data has been inserted I always get fails because the loop hasn't completed the inserts.

Google says that async code should be handled with promises but I can't find examples of promises being used in an instance like this.

Any help would be greatly appreciated

2
  • Steps to follow: 1.) Read what a Promise is carefully. 2.) Think about how the thing you just learned can be applied to your current problem. 3.) Perform code changes. Commented Mar 21, 2018 at 9:05
  • I understand promises for general use, a function will return a resolve or reject and then chain a second function but the loop would have multiple resolves Commented Mar 21, 2018 at 9:08

2 Answers 2

1

Convert each callback into a promise, and then use Promise.all

    const loDataPromises = lo_data.map(({ code, desc }) => {
      return new Promise((resolve, reject) => {
        trans.executeSql(
          "INSERT",
          [code, desc],
          function(trans, result) {
            console.log('success');
            resolve();
          },
          function(error) {
            console.log('failed');
            reject();
          }
        );
      });
    });

    Promise.all(loDataPromises)
      .then(() => {
        console.log('all done');
      });

Sign up to request clarification or add additional context in comments.

Comments

0

I haven't been able to find any clear code examples on the internet so I wanted to post the working version here as the answer. Hopefully it can benefit someone also trying to understand promises and promise loops.

After a complete overhaul I've managed to get it working in a way that makes sense. I've change it to be executed as a promise chain and then the function with the for loop is utilizing the promise all logic.

$(document).ready(function() {

   ////
   // promise chain
   ////

   console.log("BEGIN");
   f_initdatabase().then(function(result) {
      return f_defaultdata(result.db);
   }).then(function(result) {
      console.log("END");
   }).catch(function(result) {
      // abandon all hope
   });

});

////
// single promise usage
////

function f_initdatabase() {
return new Promise(function(resolve, reject) {

   console.log("   INIT DB");

   var lo_result = {db:null};

   var lv_db = window.openDatabase("thenothing", "1.0", "The Nothing DB", 2 * 1024 * 1024);

   lv_db.transaction(function(trans) {

      trans.executeSql ("create table if not exists dummydata (dd_idno integer primary key, dd_code text not null, dd_desc text not null)", [], function(trans, results) {
         console.log("   INIT DB : DONE");
         lo_result.db = lv_db;
         resolve(lo_result);
      }, function(error) {
         lo_result.db = null;
         reject(lo_result);
      });

   });

});
}

////
// loop promise all usage
////

function f_defaultdata(lv_db) {
return new Promise(function(resolve, reject) {

   console.log("   DEF DATA");

   var lo_result = {db:null};

   lv_db.transaction(function(trans) {

      var la_promises = [];

      var lo_data = [
         {dd_code:"CODE01", dd_desc:"Code 01 Desc"},
         {dd_code:"CODE02", dd_desc:"Code 02 Desc"},
         {dd_code:"CODE03", dd_desc:"Code 03 Desc"}
      ];

      for(i = 0; i < lo_data.length; i++) {

         console.log("      INS : " + i);
         trans.executeSql (" insert into dummydata (dd_code, dd_desc) values (?, ?)", [lo_data[i].dd_code, lo_data[i].dd_desc], function(trans, results) {
            la_promises.push(resolve(lo_result));
         }, function(error) {
            la_promises.push(reject(lo_result));
         });

      }

      Promise.all(la_promises).then(function(results) {
         console.log("   DEF DATA : DONE");
         lo_result.db = lv_db;
         resolve(lo_result);
      }).catch(function() {
         lo_result.db = null;
         reject(lo_result);
      });

   });

});
}

This gives the output according to the flow needed

BEGIN
   INIT DB
   INIT DB : DONE
   DEF DATA
      INS : 0
      INS : 1
      INS : 2
   DEF DATA : DONE
END

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.