17

I am dynamically loading code (functions) from a server and executing it as javascript code then storing it in an array and executing. All these snippets of code must be executed exactly once. The psuedocode follows as such

function fetch(foo){
    if (foo in fooArray){
          //Do Nothing
    else{
          //Fetch foo via Ajax and execute foo()
    }
}

The problem is vastly more complex, but essentially if I issue the below command

fetch('someFunctionName');
fetch('someFunctionName');
fetch('someFunctionName');
fetch('someFunctionName');

all four will execute the if (foo in fooArray) and assume that it is not in the array, and all four will proceed to fetch the code and execute it. I remember back in the day learning about semaphores and mutexes, are there such things for javascript.

puk
  • 16,318
  • 29
  • 119
  • 199
  • 1
    Apparantly it is possible, since jQuery does this: http://stackoverflow.com/questions/7131991/asynchronous-and-synchronous-terms – Mchl Sep 01 '11 at 07:02
  • I've written a blog about it [Why no concurrency tool in javascript](http://uzairfarooq.github.io/why-no-concurrency-control-tool-in-javascript/) – Uzair Farooq Jul 16 '15 at 06:20
  • 1
    the link is broken, should be: http://blog.uzairfarooq.com/why-no-concurrency-control-tool-in-javascript – pixel 67 Jan 04 '18 at 18:58

2 Answers2

37

JavaScript is a nice language that works great with asynchronous callbacks, timeouts, intervals and user events, yet not having any concurrency problems. This is possible because JavaScript is essentially single-threaded - given piece of code is always executed atomically and never interrupted by another thread running JavaScript.

Your fetch() function will always be executed without any interruption. If it is executed as part of the AJAX callback and if multiple AJAX callbacks are pending, they will be queued.

Another example: if you have an event handler assigned to an input element and you fire the event multiple times at once, event handlers won't be executed concurrently. Instead they will be queued and executed sequentially. This also applies to multiple events triggered by setTimeout()/setInterval().

As a side-note: this is one of the reasons why node.js is so robust: it uses only single thread and never blocks on I/O but uses callbacks instead when data is ready/event occurs.

Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • 6
    Strictly speaking [web workers](http://en.wikipedia.org/wiki/Web_Workers) allow concurrent execution of JS, but since the only interaction between web workers and "normal" JS happens via messages you *still* don't have any concurrency problems. – Joachim Sauer Sep 01 '11 at 07:07
  • Tomasz I see what you are saying, thanx. – puk Sep 01 '11 at 07:22
  • @Tomasz , if the AJAX calls take too long, maybe one might not want to have too many (more than 2 or 6 depending on the browser) pending, so I offer a caching solution below.. what do you think? – Ustaman Sangat Mar 23 '12 at 18:24
  • asynchronous, not concurrent. – Ziggy Jan 20 '14 at 17:30
  • Javascript is concurrent, but not parallel. https://blog.golang.org/concurrency-is-not-parallelism – kristianp Sep 18 '18 at 05:22
0

Javascript is essentially single-threaded so you don't need a mutex. Your fetch could set up flags such that subsequent fetch calls could avoid making ajax calls e.g.:

var beingFetched = {};//map onflight -> callbacks
function fetch(foo){
  if (foo in fooArray){
      //Do Nothing
  } else {
      if (beingFetched.foo) { //note empty array is truthy
          //register a callback
          var callback = function(r){
             //anything you need to do wit the return object r
             //maybe even eval it.
          };
          //the callback would more likely be an argument to fetch itself
          //or you could use a promise API instead so that you can at your will
          //register multiple callbacks - for error, for success etc.
          beingFetched.foo.push(callback); 
      } else {
          beingFetched.foo = [];//truthy
          //Fetch foo via Ajax and execute
          $.ajax("getFoo/"+foo).done(function() {
              _.each(beingFetched.foo, function(cb){
                  cb.apply(cb,arguments);
              });
              delete beingFetched.foo;
          });
      }
  }
}
Ustaman Sangat
  • 1,505
  • 1
  • 14
  • 26