Используя setTimeout и рекурсию, чтобы убедиться, что что-то "готово"?

Я пытаюсь найти хороший способ проверить, готов ли какой-либо асинхронный вызов или нет. У меня есть некоторая функция, которая запускает $.ajax, а в функции обратного вызова задает логическую переменную в глобальной области действия true (наряду с некоторыми другими вещами). Перед вызовом ajax эта логическая переменная имеет значение false.

Я хочу другую функцию, которая извлекает этот "другой материал". Поскольку вызов ajax асинхронен, я не могу сразу сразу его восстановить, потому что он, вероятно, еще не будет там. То, где приходит эта логическая переменная. Я думаю, что могу просто проверить, истинно ли это логическое значение каждые 100 мс, а когда это так, ТОГДА верните и верните "другой материал".

По коду, это выглядит примерно так:

window.FOO = window.FOO || {};

;(function() {
 var isReady = false;
 var stuff;

 $.ajax({
 ...
 success: function(data) {
 stuff = data;
 isReady = true;
 }
 })

 FOO.getStuff = function() {
 // How to check if it "ready"?
 };
}

... (somewhere else)...

var stuff = FOO.getStuff();

Я пробовал следующее для FOO.getStuff безрезультатно, потому что (я думаю) setTimeout является асинхронным:

FOO.getStuff = function() {
 if (isReady) {
 return stuff;
 }
 var theStuff;
 setTimeout(function() {
 theStuff = FOO.getStuff();
 }, 100);
 return theStuff;
};

Используя консоль, я вижу, что она делает правильные вещи... но первый вызов FOO.getStuff возвращается до последующих.

Есть ли лучший способ сделать это?

Изменение: Чтобы уточнить, я хочу, чтобы вызов ajax оставался асинхронным. Я прекрасно разбираюсь в том, что вызовы getStuff() синхронны, потому что вызов ajax будет очень быстрым, и в большинстве случаев getStuff() будет вызываться позже (после того, как используется некоторые вещи).

2 ответа

За ваши комментарии у меня есть ваш ответ. Чтобы решить проблему async, мы должны делать асинхронные действия.

var stuff;
var stuffQueue = [];
$.ajax({
 success: function(data) {
 stuff = data;
 if( stuffQueue.length > 0 ){
 for(var i in stuffQueue){
 var callback = stuffQueue[i];
 callback(stuff);
 }
 stuffQueue = [];
 } 
 }
});

function getStuff(callback){
 //stuff has been loaded?
 if( stuff ){
 callback(stuff);
 }else{
 stuffQueue.push(callback);
 }
}

Чтобы вызвать команду:

var something = getStuff(function(stuff){
 console.log(stuff);
});

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

Есть чтения, в которых говорится, что асинхронный ложь - это зло, я так не верю, что зло - это использовать его неправильно. Загрузка файла мастера шаблонов является хорошим примером, где async: false может работать.

Дополнительно я рекомендую вам прочитать о предметах: http://www.html5rocks.com/en/tutorials/es6/promises/


подобная идея с Дани Аранда, я хотел бы предложить вам использовать пользовательские события.

var isReady = true;

$.ajax({
 beforeSend: function() {
 isReady = false;
 },

 success: function(data) {
 isReady = true;
 $(document).trigger('display-stuff', data);
 }
});

Foo.getStuff = function(data) {
 if (!isReady) {
 $(document).one('display-stuff', Foo.getStuff);
 return;
 }

 // do something
};

licensed under cc by-sa 3.0 with attribution.