使用ajax加载字典文件,不要让iPhone Mobile Safari崩溃

Nik*_*ola 1 javascript iphone jquery mobile-safari

我有一个Web应用程序,我将(通过ajax)一个字典文件(1MB)加载到javascript数组中.我找到了Mobile Safari在10秒后崩溃的原因.但现在我想知道的是如何解决这个问题?

在上面的链接上,答案建议使用setInterval,但这意味着我必须将一个字典文件分块,然后逐个加载.这肯定可以完成,但我必须考虑到互联网的速度制作了很多块,并且要加载页面需要太多的请求(如果我使块太大,可能会发生一些移动用户将无法在给定的10秒周期内下载块.

所以,我的问题是:有没有人遇到过这种问题,你是怎么做到的?理解正确方向的普遍推动.

编辑:这是我用来加载字典的js代码:

var dict = new Trie();

$.ajax({
    url: 'data/dictionary_342k_uppercase.txt',
    async: true,
    success: function (data) {
        var words = data.split('\n');
        for (var i = words.length - 1; i >= 0; i--) {
            dict.insert(words[i]);
        }           
    },
    error: function(){
        $('#loading-message').text("Problem s rje?nikom");
    }
});
Run Code Online (Sandbox Code Playgroud)

Trie.js:

function Trie () {
  var ALPHABET_SIZE = 30;
  var ASCII_OFFSET = 'A'.charCodeAt();

  this.children = null;
  this.isEndOfWord = false;

  this.contains = function (str) {
    var curNode = this;

    for (var i = 0; i < str.length; i++) {
      var idx = str.charCodeAt(i) - ASCII_OFFSET;
      if (curNode.children && curNode.children[idx]) {
        curNode = curNode.children[idx];
      } else {
        return false;
      }
    }

    return curNode.isEndOfWord;
  }

  this.has = function (ch) {
    if (this.children) {
      return this.children[ch.charCodeAt() - ASCII_OFFSET] != undefined;
    }
    return false;
  }

  this.next = function (ch) {
    if (this.children) {
      return this.children[ch.charCodeAt() - ASCII_OFFSET];
    }
    return undefined;
  }

  this.insert = function (str) {
    var curNode = this;

    for (var i = 0; i < str.length; i++) {
      var idx = str.charCodeAt(i) - ASCII_OFFSET;

      if (curNode.children == null) {
        curNode.children = new Array(ALPHABET_SIZE);
        curNode = curNode.children[idx] = new Trie();
      } else if (curNode.children[idx]) {
        curNode = curNode.children[idx];
      } else {
        curNode = curNode.children[idx] = new Trie();
      }
    }

    curNode.isEndOfWord = true;
    return curNode;
  }
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*man 7

一旦开始在JS中进行处理,这是一个非常常见的问题.如果Mobile Safari问题是原因,那么你想要做的是弄清楚CPU时间在这里的位置.

我假设它是dict.insert()循环而不是data.split()调用(这将更难管理).

这里的想法是将dict.insert()循环分成功能块,这些功能块可以在顺序循环中异步调用(这是setupBuildActions函数所做的).在第一个块之后,每个后续块都被调用via setTimeout,这有效地重置了JS运行时中的函数时间计数器(这似乎正在扼杀你的进程).

使用Sequencer功能意味着您还可以控制函数的运行顺序(它们始终按照它们在此处生成的顺序运行,并且不会同时调度两个或多个函数执行).这比setTimeout没有回调的数千个呼叫更有效.您的代码保留对执行顺序的控制(这也意味着您可以在执行期间进行更改),并且JS运行时不会因计划的执行请求而过载.

您可能还想查看https://github.com/michiel/sequencer-js上的节点项目以获取更多测序示例,并查看http://ejohn.org/blog/how-javascript-timers-work/以获取解释setTimeout在不同的平台上.

var dict = new Trie();

// These vars are accessible from all the other functions we're setting up and
// running here

var BLOCKSIZE     = 500;
var words         = [];
var buildActions  = [];

function Sequencer(funcs) {
  (function() {
    if (funcs.length !== 0) {
      funcs.shift()(arguments.callee);
    }
  })();
}

// Build an Array with functions that can be called async (using setTimeout)

function setupBuildActions() {
  for (var offset=0; offset<words.length; offset+= BLOCKSIZE) {
    buildActions.push((function(offset) {
      return function(callback) {
        for (var i=offset; i < offset + BLOCKSIZE ; i++) {
          if (words[i] !== null) { // ugly check for code brevity
            dict.insert(words[i]);
          }
        }           
        // This releases control before running the next dict.insert loop
        setTimeout(callback, 0);
      };
    })(offset));
  }
}

$.ajax({
    url: 'data/dictionary_342k_uppercase.txt',
    async: true,
    success: function (data) {
      // You might want to split and setup these calls 
      // in a setTimeout if the problem persists and you need to narrow it down
      words = data.split('\n');
      setupBuildActions();
      new Sequencer(buildActions);
    },
    error: function(){
      $('#loading-message').text("Problem s rje?nikom");
    }
});
Run Code Online (Sandbox Code Playgroud)