Существуют ли какие-либо атомарные операции JavaScript, чтобы справиться с асинхронной природой Ajax?

Я динамически загружаю код (функции) с сервера и выполняю его как код JavaScript, затем сохраняю его в массиве и выполняю. Все эти фрагменты кода должны быть выполнены ровно один раз. Псевдокод следует как таковой

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

Проблема намного сложнее, но по сути, если я введу команду ниже

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

все четыре выполнят if (foo in fooArray) и предположим, что его нет в массиве, и все четыре продолжат извлекать код и выполнять его. Я помню, как в те дни, узнав о семафорах и мьютексах, существуют ли такие вещи для javascript.

2 ответа

Решение

JavaScript - хороший язык, который отлично работает с асинхронными обратными вызовами, тайм-аутами, интервалами и пользовательскими событиями, но не имеет проблем с параллелизмом. Это возможно, потому что JavaScript по сути однопоточный - данный фрагмент кода всегда выполняется атомарно и никогда не прерывается другим потоком, выполняющим JavaScript.

Ваш fetch() Функция всегда будет выполняться без прерывания. Если он выполняется как часть обратного вызова AJAX и если ожидают несколько обратных вызовов AJAX, они будут поставлены в очередь.

Другой пример: если у вас есть обработчик событий, назначенный элементу ввода, и вы запускаете событие несколько раз одновременно, обработчики событий не будут выполняться одновременно. Вместо этого они будут поставлены в очередь и выполнены последовательно. Это также относится к нескольким событиям, вызванным setTimeout()/setInterval(),

Как примечание: это одна из причин, почему node.js настолько устойчив: он использует только один поток и никогда не блокирует ввод-вывод, а вместо этого использует обратные вызовы, когда данные готовы / происходит событие.

Javascript по сути однопоточный, поэтому вам не нужен мьютекс. Ваша выборка может установить флаги так, чтобы последующие вызовы выборки могли избежать вызовов ajax, например:

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;
          });
      }
  }
}
Другие вопросы по тегам