I was using underscorejs to loop through a list of 60 00 ICD codes to put in a lunr.js full text search index, like this:
_.each(dictionary, function (document) { index.add(document); });This took about 5 seconds and was freezing the browser page.
I then tried using async.js, thinking that it would run my code asynchronously giving the browser some time to draw.
async.eachSeries(Object.keys(dictionary), function (key, callback)
{
  index.add(dictionary[key]);
  callback(); //and also tried 'nextTick' to do this asynchronously
});Unfortunately that made no difference. I realised although this code is being called asynchronously once called it still monopolises the processor for five seconds.
I then tried putting my code in a loop and every 100 or 1000 entries taking a break using setTimeout(100) to let the browser handle events. This also made no difference.
Finally I tried to use a web worker - an HTML 5 background thread specifically provided for intensive calculations that might freeze the browser. For a tutorial see http://www.html5rocks.com/en/tutorials/workers/basics/. This worked perfectly. My main thread (UI code) now looks like this:
function createFullTextSearchIndexInWebWorker(dictionary)
{
  var worker = new Worker("Content/js/workers/AddDocumentsToSearchIndex.js"); //create a web worker to add documents to full text index in the background
  worker.onmessage = function (e) //update our full text when the worker sends us its output when finished
  {
     _icdDiagnosisCodesFullTextIndex = lunr.Index.load(JSON.parse(e.data))
     worker.terminate(); //kill the thread cos it no longer benefits us and must die
  }
  worker.postMessage(dictionary); //start the worker by giving it the documents to index
}and my web worker js file looks like this
(function ()
{
  self.importScripts
  (
    "../../bower_components/underscore/underscore.js"
    ,"../../bower_components/lunr.js/lunr.min.js"
  );
  self.addEventListener
  (
    'message'
    , function (e)
    {
      var index = lunr(function ()
      {
        this.field('Name');
        this.field('Code');
        this.field('Instructions_Includes');
        this.field('Instructions_Excludes');
        this.field('Instructions_Notes');
        this.field('Instructions_Terminology');
        this.field('Instructions_Morbidity');
        this.ref('Id');
      });
      _.each(e.data, function (document) { index.add(document); });
      self.postMessage(JSON.stringify(index.toJSON()));
    }
    , false
  );
}());