Skip to content Skip to sidebar Skip to footer

Prevent Browser Freezing And Crashing For Long Time Calculation

I need check in my database names who are duplicated and change this name to avoid duplicates. I using script suggested by @Jefré N. function eliminateDuplicates() { var re

Solution 1:

I think that the most cumbersome part of your code is the DOM access: getting input values and updating them.

According to the webworkers documentation, webworkers have their limitations and one of them is DOM manipulation. So I'd discard that option.

In order to fix things, I'd do as follows:

  1. Improve your eliminateDuplicates algorithm (make it faster).
  2. Make eliminateDuplicates asynchronous: divide the set of elements in smaller ones and perform each calculation in a different event loop tick (setTimeout).

Here I present you a solution I've come up with. Hope it gives you some ideas and help you to solve your problem.

First, I tweaked a bit eliminateDuplicates (I called it modifyDOM)

functionmodifyDOM(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];
        }
    }
}

I avoided using jQuery inside the main loop because its wrapper makes things slower and in your case it wasn't worth using it. These small changes improved performance in 100ms per 10.000 elements (give it or take).

I created two functions that use modifyDOM: one asynchronous and other synchronous.

functionparseElementsNonBlocking(elements, maxChunkSize) {
    var repeats = {},
        nChunks = Math.floor(elements/maxChunkSize),
        i = 0,
        j = 1;

    //loop through inputs and update repeatsfor(; i < nChunks; i++, j++) {
        setTimeout(modifyDOM.bind(null, elements.slice(i, j*maxChunkSize), repeats), 0);
    }
    // RestsetTimeout(modifyDOM.bind(null, elements.slice(i), repeats), 0);
}

functionparseElementsBlocking(elements) {
    var repeats = {};

    //loop through inputs and update repeatsmodifyDOM(elements, repeats);
}

Lastly and in order to test everything, a function that executes when the DOM is ready and creates 10.000 inputs. It then outputs how long it takes to run any of the above methods.

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

Here you have the fiddle to test it all.

Solution 2:

here is a solution using OODK-JS to calculate the sum of an array of 1.000.000 entries through webworkers.

This solution implements the producer/consumer design pattern using the SynchronizedQueue foundation class: the producer (main thread) generate a task for each chunk of the array and add it to queue. The consumer (webworker) take a task in the queue and execute it until no one left. Once all tasks are executed, the producer display the final result

// 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 arraysvarArrayHelper = $.class(function($, µ, _){

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

                // slice an array into chunks using chunkLength argument// as delimiter 
                $.public(functionslice(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(functionrandom(len){

                  var arr = [];

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

                  return arr;
                })
              });

            });

            // class to handle a pool of threadvarThreadPool = $.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(functionstart(){

                // bind listenersvar threadListener= $.new(Producer);

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

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

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

                  consumer.start();
                }

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

              });

            });

            // Event Listener for the threadvarProducer = $.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());

                }elseif(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 valuesvar myHugeArray = ArrayHelper.self.random(1000000);

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

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

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

              var chunk = chunks[i];

              // create a task for each chunk of the arrayvar 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 queuevar 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 ...');
          });

The consumer (webworker)

//consumer.jsOODK.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 synchronizerOODK.foundation.util.concurrent.SynchronizedObject.self.start();

  // EventListener Class to handle synchronized queue events
  $.implements(OODK.foundation.EventListener).class(functionConsumer($, µ, _){

    $.protected(function__processEvent(evt){

      if(evt.getType() == 'synchronizedQueue.ready'){
        //queue is synchronizedvar queue = evt.getTarget();

        // bind listener
        $.on(queue, 'synchronizedQueue.elementRetrieved', this);

        // take a task: get the heap of the stack and delete it
        queue.take();

      }elseif(evt.getType() == 'synchronizedQueue.elementRetrieved'){

        // task is retrieved from the queuevar task = evt.getData();

        var queue = evt.getTarget();

        // execute the taskvar 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);

});

The task class to implement the custom logic

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

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

    // 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(functionexecute(){

      var result = 0;

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

      return result;
    });

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

      $.public(functionfactory(chunk){

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

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

});

Post a Comment for "Prevent Browser Freezing And Crashing For Long Time Calculation"