Javascript 防止长时间计算时浏览器冻结和崩溃

Javascript 防止长时间计算时浏览器冻结和崩溃,javascript,freeze,web-worker,Javascript,Freeze,Web Worker,我需要签入重复的数据库名称,并更改此名称以避免重复。我正在使用@JefréN建议的脚本 function eliminateDuplicates() { var repeats = {}; var error = false; //cache inputs var $inputs = $("input[type='text']"); //loop through inputs and update repeats for (i = 0; i

我需要签入重复的数据库名称,并更改此名称以避免重复。我正在使用@JefréN建议的脚本

function eliminateDuplicates() {

    var repeats = {};
    var error = false;

    //cache inputs
    var $inputs = $("input[type='text']");

    //loop through inputs and update repeats
    for (i = 0; i < $inputs.length; ++i) {
        //cache current element
        var cur = $inputs[i];

        //remove class
        $(cur).removeClass("double-error");

        //get text of this element
        var text = $(cur).val();

        //no text -- continue
        if (text === "") {
            continue;
            }
        //first time we've came across this value -- intialize it's counter to 1
        if ((text in repeats) === false) {
            repeats[text] = 1;
            }
        //repeat offender. Increment its counter.
        else {
            repeats[text] = repeats[text] + 1;
            }

        //update the the value for this one
        $(cur).val(text + "-" + repeats[text]);
        }

    return error; // always returns false since I'm not sure
                  // when it's supposed to return true.
    }
没有成功。Chrome冻结,IE11浏览器,Firefox崩溃。怎么了? 我的记录显示在HTML表中


有些人建议使用网络工作者。也许这里有人有这种做法,并有一个运行示例?

这里有一个解决方案,使用OODK-JS通过webworkers计算1.000.000个条目数组的总和

此解决方案使用SimuleDealQueoundFoundation类实现生产者/消费者设计模式:生产者(主线程)为数组的每个块生成任务并将其添加到队列中。使用者(webworker)接受队列中的任务并执行它,直到无人离开。执行所有任务后,生产者将显示最终结果

// main.js (producer)
          OODK.config({
            'path': {
              'oodk': '../src',
              'workspace': 'workspace'
            }
          });

          OODK(function($, _){

            $.import('{oodk}/foundation/utility/Thread', '[util.concurrent]', '{workspace}/project/Task');

            // array helper class to handle arrays
            var ArrayHelper = $.class(function($, µ, _){

              $.static(function($, µ, _){

                // slice an array into chunks using chunkLength argument
                // as delimiter 
                $.public(function slice(arr, chunkLength){

                  return arr.reduce(function(arr, val, index){

                    var chunkIndex = Math.floor(index/chunkLength); 

                    if(!arr[chunkIndex]) {
                      arr[chunkIndex] = [];
                    }

                    arr[chunkIndex].push(val);

                    return arr;
                  }, []);
                });

                // generate an array of len argument length
                // containing random values 
                $.public(function random(len){

                  var arr = [];

                  for(var i =0; i<len; i++){
                    arr.push(Math.random()*10);
                  }

                  return arr;
                })
              });

            });

            // class to handle a pool of thread
            var ThreadPool = $.class(function($, µ, _){

              // number of threads to instantiate
              $.private('num');

              // queue to works with
              $.private('queue');

              $.public(function __initialize(num, queue){

                _.num = num;

                _.queue = queue;
              });

              // start the pool
              $.public(function start(){

                // bind listeners
                var threadListener= $.new(Producer);

                for(var i=0; i<_.num; i++){

                  // instantiate consumers
                  var consumer = $.new(OODK.foundation.util.Thread, "consumer.js");

                  $.on(consumer, 'thread.ready', threadListener);

                  consumer.start();
                }

                $.on(_.queue, 'synchronizedQueue.taskDone', threadListener);

              });

            });

            // Event Listener for the thread
            var Producer = $.implements(OODK.foundation.EventListener).class(function($, µ, _){

              // number of task done
              $.private('taskDone', 0);

              // final result
              $.private('finalResult', 0);

              $.private(function __processEvent(evt){

                if(evt.getType() === 'thread.ready'){

                  // the thread is ready, synchronize the queue with the current thread
                  queue.synchronize(evt.getTarget());

                }else if(evt.getType() == 'synchronizedQueue.taskDone'){
                  //message received from the consumer that it has performed a task

                  _.taskDone++;

                  var cqueue = evt.getTarget();

                  var chunkResult = evt.getData();

                  _.finalResult += chunkResult;

                  jQuery('#chunksDone').text(_.taskDone);

                  if(cqueue.getCapacity() == _.taskDone){

                    // once all tasks are performed display the final result
                    $.log('final sum is ' + _.finalResult);
                  }else{
                    // each time a chunk is calculated display the intermediate result 
                    $.log('intermediate result ' + _.finalResult);
                  }
                }
              });
            });

            // generate a large array of 1.000.000 random values
            var myHugeArray = ArrayHelper.self.random(1000000);

            // split this array into chunks of 2500 length
            var chunks = ArrayHelper.self.slice(myHugeArray, 25000);

            // instantiate a synchronized queue setted as size the number of chunks
            var queue = $.new(OODK.foundation.util.concurrent.SynchronizedQueue, chunks.length);

            // for each chunk create a task and add it to queue
            for(var i=0; i<chunks.length; i++){

              var chunk = chunks[i];

              // create a task for each chunk of the array
              var task = OODK.project.Task.self.factory(chunk);

              // and add it to the queue
              queue.put(task);
            }

            // instantiate a pool of 2 threads working on the given queue
            var threadPool = $.new(ThreadPool, 2, queue);

            // start the pool
            threadPool.start();

            $.log('calculate the sum of an array of 1.000.000 entries using 2 threads ...');
          });
用于实现自定义逻辑的任务类

OODK('project', function($, _){

  $.public().implements(OODK.foundation.Serializable).class(function Task($, µ, _){

    // the array chunk to calculate
    $.private('chunk');

    $.public(function __initialize(chunk){
      _.chunk = chunk;
    });

    // calculate the sum of all entries of a chunk
    // implements the custom logic here
    $.public(function execute(){

      var result = 0;

      for(var i=0; i<_.chunk.length; i++){
        result += _.chunk[i];
      }

      return result;
    });

    $.static(function($, µ, _){

      $.public(function factory(chunk){

        var task = $.new($.ns.Task, chunk);

        return task;
      });
    });
  });

});
OODK('project',函数($,){
实现(OODK.Frime.SerialItaby.)类(函数任务($,^,)){
//要计算的数组块
$.private('chunk');
$.public(函数u_初始化(块){
_.chunk=chunk;
});
//计算块中所有项的总和
//在这里实现自定义逻辑
$.public(函数执行(){
var结果=0;

对于(var i=0;i我认为代码中最麻烦的部分是DOM访问:获取输入值并更新它们

根据,webworkers有其局限性,其中之一就是DOM操作。所以我放弃了这个选项

为了解决问题,我会做如下工作:

  • 改进
    消除重复的算法(使其更快)
  • 使
    eliminatedReplicates
    asynchronous:将元素集划分为较小的元素,并在不同的事件循环勾选(setTimeout)中执行每个计算
  • 在这里,我给你们介绍一个我想出的解决方案。希望它能给你们一些想法,帮助你们解决你们的问题

    首先,我调整了一点
    消除了重复项
    (我称之为
    modifyDOM

    最后,为了测试一切,一个在DOM就绪时执行并创建10000个输入的函数,然后输出运行上述任何方法所需的时间

    $(function () {
        var inputsDiv = $('#inputs'), i, time;
        for (i = 0; i < 10000; i++) {
            var val = i % 3 === 0 ? 'Mickey' : (i % 3 === 1 ? 'Mouse' : '');
            inputsDiv.append('<input type="text" class="double-error" name="FirstName" value="' + val + '">');
        }
    
        time = Date.now();
        //parseElementsBlocking($("input[type='text']"));
        parseElementsNonBlocking($("input[type='text']"), 100);
        console.log(Date.now() - time);
    });
    
    $(函数(){
    var inputsDiv=$('输入'),i,时间;
    对于(i=0;i<10000;i++){
    var val=i%3==0?'Mickey':(i%3==1?'Mouse':'');
    输入iv.追加(“”);
    }
    时间=日期。现在();
    //parseElementsBlocking($(“输入[type='text']”);
    ParseElementsNonblock($(“输入[type='text']),100);
    console.log(Date.now()-time);
    });
    

    您可以在这里测试所有内容。

    setTImeout
    可以,您的问题是什么?您尝试过吗?发布您尝试过的内容,最好是在jsfiddle.net上,并发布一个链接。使用webworkers Ok谢谢您的建议。更新的用户尝试过这个。也许有些人有很好的工作示例?问候@KęstutisBanišauskas!我有几个问题。1。为什么需要在客户端执行此操作?2.您是否仍在访问
    s中的值?如果没有,您将如何循环使用所需的值?@JefréN。谢谢,当页面从数据库中提交所有数据时。所有数据都将放入输入字段,以便进一步检查重复项并使用脚本添加数字。所以,当记录达到100条时,一切正常。当记录达到数千条时,浏览器会冻结。并弹出警报。因此,我需要一些解决方案来防止这种情况。我想也许webworker可以提供帮助,但在这里没有经验。并且需要添加一些加载栏,以了解backgrond进程正在运行。您好,感谢您的回答。似乎我遗漏了一些我可以让它工作。这个函数“function modifyDOM(elements,repeats)”对我不起作用。
    //consumer.js
    
    OODK.config({
      'path': {
        'oodk': '../src',
        'workspace': 'workspace'
      }
    });
    
    OODK(function($, _){
    
      // import the concurrent API package as well as the task class
      $.import('[util.concurrent]', '{workspace}/project/Task');
    
      // start the synchronizer
      OODK.foundation.util.concurrent.SynchronizedObject.self.start();
    
      // EventListener Class to handle synchronized queue events
      $.implements(OODK.foundation.EventListener).class(function Consumer($, µ, _){
    
        $.protected(function __processEvent(evt){
    
          if(evt.getType() == 'synchronizedQueue.ready'){
            //queue is synchronized
    
            var queue = evt.getTarget();
    
            // bind listener
            $.on(queue, 'synchronizedQueue.elementRetrieved', this);
    
            // take a task: get the heap of the stack and delete it
            queue.take();
    
          }else if(evt.getType() == 'synchronizedQueue.elementRetrieved'){
    
            // task is retrieved from the queue
    
            var task = evt.getData();
    
            var queue = evt.getTarget();
    
            // execute the task
            var result = task.execute();
    
            // notify the producer that the task is done
            queue.notify('synchronizedQueue.taskDone', result);
    
            if(queue.remainingElements()>0){
              // at least one task is still in the queue, take it
    
              queue.take();
            }
    
          }
        });
      });
    
      var threadListener = $.new(_.Consumer);
    
      // global listener for the synchronizedQueue.ready event 
      // triggered when the synchronzied queue is synchronized with this thread
      $.on('synchronizedQueue.ready', threadListener);
    
    });
    
    OODK('project', function($, _){
    
      $.public().implements(OODK.foundation.Serializable).class(function Task($, µ, _){
    
        // the array chunk to calculate
        $.private('chunk');
    
        $.public(function __initialize(chunk){
          _.chunk = chunk;
        });
    
        // calculate the sum of all entries of a chunk
        // implements the custom logic here
        $.public(function execute(){
    
          var result = 0;
    
          for(var i=0; i<_.chunk.length; i++){
            result += _.chunk[i];
          }
    
          return result;
        });
    
        $.static(function($, µ, _){
    
          $.public(function factory(chunk){
    
            var task = $.new($.ns.Task, chunk);
    
            return task;
          });
        });
      });
    
    });
    
    function modifyDOM(elements, repeats) {
        var input, text, i = 0;
        for (; i < elements.length; i++) {
            input = elements[i];
            text = input.value;
            // Remove class.
            input.className = input.className.replace(/\bdouble-error\b/, '');
            if (text) {
                repeats[text] = ~~repeats[text] + 1;
                input.value = text + "-" + repeats[text];
            }
        }
    }
    
    function parseElementsNonBlocking(elements, maxChunkSize) {
        var repeats = {},
            nChunks = Math.floor(elements/maxChunkSize),
            i = 0,
            j = 1;
    
        //loop through inputs and update repeats
        for(; i < nChunks; i++, j++) {
            setTimeout(modifyDOM.bind(null, elements.slice(i, j*maxChunkSize), repeats), 0);
        }
        // Rest
        setTimeout(modifyDOM.bind(null, elements.slice(i), repeats), 0);
    }
    
    function parseElementsBlocking(elements) {
        var repeats = {};
    
        //loop through inputs and update repeats
        modifyDOM(elements, repeats);
    }
    
    $(function () {
        var inputsDiv = $('#inputs'), i, time;
        for (i = 0; i < 10000; i++) {
            var val = i % 3 === 0 ? 'Mickey' : (i % 3 === 1 ? 'Mouse' : '');
            inputsDiv.append('<input type="text" class="double-error" name="FirstName" value="' + val + '">');
        }
    
        time = Date.now();
        //parseElementsBlocking($("input[type='text']"));
        parseElementsNonBlocking($("input[type='text']"), 100);
        console.log(Date.now() - time);
    });