-1

I have a huge and slow synchronous function which I wish to wrap it inside a promise to use it asynchronously. Although this function contains secondary operations, is good to be executed without get the interface stuck (avoiding the user's rage :D).

What I did is the following (commons.js, separate javascript file):

exports default {
  myHugeFunction: function(params) {
   //lots...lots...lots..of synchronous things
  }
}

Where I call it?

Vuejs store module

import commons from '/path/to/commons'
export default {
  actions: {
    updateInterface: function() {
     //overlay on
     //some syncronous stuff...
      Q.fcall(function () {
        commons.myHugeFunction(params);
      }
     //some others syncronous stuff...
     //overlay off
    }
  }
}

Even so, it seems to work fine but I got the entire frontend stuck since the huge function has finished. I use to put an overlay before the execution and after that but i can't see it eve if there's in the dom (but that's probably another out of scope problem...).

I imagine it's execution like something that could be handled by a separate thread so the user, during this time, can do others stuff.

Is because "maybe" the application is entirely in the front-end (browser)?

Andrea Grimandi
  • 631
  • 2
  • 8
  • 32
  • no matter where you put it, if you have a huge synchronous function that blocks io it's gonna block io. fix the function itself. – Kevin B May 15 '17 at 16:22
  • Thank you so much for the useful answer! Now the problem it's clear. That's shared code with another team that is veeeeeery proud of his work :D and cannot touch for any reason (that code) so we have to workaround the problem, can be possible too? YES or NO could be also a good answer, just for know how can we move from now :) – Andrea Grimandi May 15 '17 at 16:42

1 Answers1

0

You could use a web worker for this, on the condition that myHugeFunction does not use any global variables that are only available in the window context. So for instance, it cannot interact with the DOM. You need to pass all external dependencies as parameters, or include the dependencies in the web worker context.

Here is how it would look like:

Move myHugeFunction out of commons.js into a new, separate worker.js file that you should not import. Your worker.js file should look like this:

function myHugeFunction(...params) {
   //lots...lots...lots..of synchronous things
   console.log('parameters', params);
   return 'myHugeFunction return value';
}

onmessage = function(e) {
    postMessage(myHugeFunction(...e.data));
}

In your commons.js you could define this helper function promiseWork:

exports default {
    promiseWork: function(script, params) {
        return new Promise(function (resolve, reject) {
            var worker = new Worker(script);
            worker.onmessage = function(e) {
                resolve(e.data);
            }
            worker.onerror = function(e) {
                reject('[' + e.filename + ':' + e.lineno + '] ' + e.message);
            }
            worker.postMessage(params);
        });
    }
}

In your Vuejs store module you would call promiseWork with the script name and parameters (an array) as arguments:

export default {
    actions: {
        updateInterface: function() {
            //overlay on
            //some synchronous stuff...
            promiseWork('worker.js', params).then(function () {
                console.log('huge work completed asynchronously');
                //some other stuff...
                //overlay off
            });
        }
    }
}
trincot
  • 317,000
  • 35
  • 244
  • 286