Существуют ли какие-либо атомарные операции 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;
});
}
}
}