【问题标题】:Websql queued execution - iOS6 Mobile SafariWebsql 排队执行 - iOS6 Mobile Safari
【发布时间】:2012-09-26 19:17:49
【问题描述】:

自从 iOS6 发布以来,我的 web 应用程序遇到了一系列错误,其中最糟糕的是我几乎 100% 肯定的问题是 websql 事务正在排队。当我第一次在移动 safari(ipad)中加载应用程序时,交易工作正常。然后,如果我关闭 safari 并再次打开它,事务似乎已排队并且永远不会执行。

如果我打开开发工具并运行一个简单的alert,这些方法将触发,如果我只是点击重新加载事务也可以正常工作,或者如果我将数据库事务的运行延迟 1 秒或它可以工作也很好。

我不想运行 setTimeout 来运行事务。

这是 Safari 实施后的缓存问题吗?

如果有人对如何解决此问题有任何好的想法,请在下面回答。

提前致谢。

【问题讨论】:

    标签: javascript ios html mobile web-sql


    【解决方案1】:

    这可能不是错误。您可能会不必要地使用一系列事务。您可以在每个事务中使用多个请求。 onsuccess回调,可以复用事务。它应该工作。同时,限制每个事务的请求数。 setTimeout 永远不需要。

    这是如何使用单个事务插入多个对象

    /**
    * @param {goog.async.Deferred} df
    * @param {string} store_name table name.
    * @param {!Array.<!Object>} objects object to put.
     * @param {!Array.<(Array|string|number)>=} opt_keys
    */
    ydn.db.req.WebSql.prototype.putObjects = function (df, store_name, objects, opt_keys) {
    
      var table = this.schema.getStore(store_name);
      if (!table) {
        throw new ydn.db.NotFoundError(store_name);
      }
    
      var me = this;
      var result_keys = [];
      var result_count = 0;
    
      /**
       * Put and item at i. This ydn.db.core.Storage will invoke callback to df if all objects
       * have been put, otherwise recursive call to itself at next i+1 item.
       * @param {number} i
       * @param {SQLTransaction} tx
       */
      var put = function (i, tx) {
    
        // todo: handle undefined or null object
    
        var out;
        if (goog.isDef(opt_keys)) {
          out = table.getIndexedValues(objects[i], opt_keys[i]);
        } else {
          out = table.getIndexedValues(objects[i]);
        }
        //console.log([obj, JSON.stringify(obj)]);
    
        var sql = 'INSERT OR REPLACE INTO ' + table.getQuotedName() +
            ' (' + out.columns.join(', ') + ') ' +
            'VALUES (' + out.slots.join(', ') + ');';
    
        /**
         * @param {SQLTransaction} transaction transaction.
         * @param {SQLResultSet} results results.
         */
        var success_callback = function (transaction, results) {
          result_count++;
          result_keys[i] = goog.isDef(out.key) ? out.key : results.insertId;
          if (result_count == objects.length) {
            df.callback(result_keys);
          } else {
            var next = i + ydn.db.req.WebSql.RW_REQ_PER_TX;
            if (next < objects.length) {
              put(next, transaction);
            }
          }
        };
    
        /**
         * @param {SQLTransaction} tr transaction.
         * @param {SQLError} error error.
         */
        var error_callback = function (tr, error) {
          if (ydn.db.req.WebSql.DEBUG) {
            window.console.log([sql, out, tr, error]);
          }
          df.errback(error);
          return true; // roll back
        };
    
        //console.log([sql, out.values]);
        tx.executeSql(sql, out.values, success_callback, error_callback);
      };
    
      if (objects.length > 0) {
        // send parallel requests
        for (var i = 0; i < ydn.db.req.WebSql.RW_REQ_PER_TX && i < objects.length; i++) {
          put(i, this.getTx());
        }
      } else {
        df.callback([]);
      }
    };
    

    关于事务队列,为了健壮性,最好由应用程序而不是由 SQLite 处理。基本上我们可以在开始新事务之前观察事务complete 事件。只要它们受到控制,运行多个事务也可以。失控将在循环下打开交易。一般来说,我只会打开几笔交易。

    这是交易的排队方式:

    /**
     * Create a new isolated transaction. After creating a transaction, use
     * {@link #getTx} to received an active transaction. If transaction is not
     * active, it return null. In this case a new transaction must re-create.
     * @export
     * @param {Function} trFn function that invoke in the transaction.
     * @param {!Array.<string>} store_names list of keys or
     * store name involved in the transaction.
     * @param {ydn.db.TransactionMode=} opt_mode mode, default to 'readonly'.
     * @param {function(ydn.db.TransactionEventTypes, *)=} oncompleted
     * @param {...} opt_args
     * @override
     */
    ydn.db.tr.TxStorage.prototype.transaction = function (trFn, store_names, opt_mode, oncompleted, opt_args) {
    
      //console.log('tr starting ' + trFn.name);
      var scope_name = trFn.name || '';
    
      var names = store_names;
      if (goog.isString(store_names)) {
        names = [store_names];
      } else if (!goog.isArray(store_names) ||
        (store_names.length > 0 && !goog.isString(store_names[0]))) {
        throw new ydn.error.ArgumentException("storeNames");
      }
      var mode = goog.isDef(opt_mode) ? opt_mode : ydn.db.TransactionMode.READ_ONLY;
      var outFn = trFn;
      if (arguments.length > 4) { // handle optional parameters
        var args = Array.prototype.slice.call(arguments, 4);
        outFn = function () {
          // Prepend the bound arguments to the current arguments.
          var newArgs = Array.prototype.slice.call(arguments);
           //newArgs.unshift.apply(newArgs, args); // pre-apply
          newArgs = newArgs.concat(args); // post-apply
          return trFn.apply(this, newArgs);
        }
      }
      outFn.name = scope_name;
    
      var me = this;
    
      if (this.mu_tx_.isActive()) {
        //console.log(this + ' active')
        this.pushTxQueue(outFn, store_names, mode, oncompleted);
      } else {
        //console.log(this + ' not active')
        var transaction_process = function (tx) {
    
          me.mu_tx_.up(tx, scope_name);
    
          // now execute transaction process
          outFn(me);
    
          me.mu_tx_.out(); // flag transaction callback scope is over.
          // transaction is still active and use in followup request handlers
        };
    
        var completed_handler = function (type, event) {
          me.mu_tx_.down(type, event);
          /**
           * @preserve_try
           */
          try {
            if (goog.isFunction(oncompleted)) {
              oncompleted(type, event);
            }
          } catch (e) {
            // swallow error. document it publicly.
            // this is necessary to continue transaction queue
            if (goog.DEBUG) {
              throw e;
            }
          } finally {
            me.popTxQueue_();
          }
        };
    
        if (ydn.db.tr.TxStorage.DEBUG) {
          window.console.log(this + ' transaction ' + mode + ' open for ' + JSON.stringify(names) + ' in ' + scope_name);
        }
        this.storage_.newTransaction(transaction_process, names, mode, completed_handler);
      }
    
    };
    

    【讨论】:

    • 感谢您的回复。我正在使用单个事务来执行多个请求。如我的问题所述,直到 iOS6 才引入此问题,如果我延迟事务调用或重新加载页面,则可以正常工作。仅当页面从关闭的 safari 加载时才会发生。
    • 我明白了。我的猜测是 iOS6 收紧请求。可能是其他原因。一些源代码可能有助于发现问题。
    【解决方案2】:

    事实证明,在 websql 之前初始化 Facebook 会导致问题。注释掉 FB 后,应用程序运行正常,这也是 setTimeout 解决问题的原因; fb api 准备好了。执行线程是如何被阻塞的,我不知道。

    所以,对于任何使用 FB 然后尝试执行 websql 事务的人...延迟 FB!

    虽然,websql 在 safari 加载时运行速度仍然有点慢...

    【讨论】:

    • 当电子邮件对话框打开并且 websql 事务尝试执行时,我再次遇到了这个问题。它永远不会执行!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-27
    • 2011-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多