【问题标题】:Javascript Execute at end of Async LoopJavascript 在异步循环结束时执行
【发布时间】:2018-03-21 09:00:14
【问题描述】:

我对 Javascript 中的异步代码感到很糟糕,现在已经卡在某事上一段时间了。

我正在使用 WebSql 并且刚刚完成数据库初始化步骤,但是其中一个循环没有按我期望的方式执行。

$(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");

    });

}

但是指示结束的日志在 for 循环完成之前执行。如果我尝试验证数据是否已插入,我总是会失败,因为循环尚未完成插入。

Google 表示应该使用 Promise 处理异步代码,但我找不到在这样的实例中使用 Promise 的示例。

任何帮助将不胜感激

【问题讨论】:

  • 要遵循的步骤: 1.) 仔细阅读Promise 是什么。 2.) 想想你刚刚学到的东西如何应用到你当前的问题上。 3.) 执行代码更改。
  • 我理解一般用途的承诺,一个函数将返回一个解析或拒绝,然后链接第二个函数,但循环将有多个解析

标签: javascript loops for-loop asynchronous


【解决方案1】:

将每个回调转化为一个promise,然后使用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');
      });

【讨论】:

    【解决方案2】:

    我无法在互联网上找到任何清晰的代码示例,所以我想在这里发布工作版本作为答案。希望它可以帮助那些试图理解 Promise 和 Promise 循环的人。

    在彻底检修后,我设法让它以一种有意义的方式工作。我已将其更改为作为 Promise 链执行,然后带有 for 循环的函数使用 Promise all 逻辑。

    $(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);
          });
    
       });
    
    });
    }
    

    这会根据需要的流程给出输出

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

    【讨论】:

      猜你喜欢
      • 2017-10-20
      • 1970-01-01
      • 2020-02-04
      • 1970-01-01
      • 1970-01-01
      • 2020-02-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多