2012-02-24 7 views
0

Я программировал несколько лет, но я новичок в JavaScript. Я пытаюсь создать хакерскую версию стандартной функции «уведомлять» потока. Я запускаю ряд запросов данных ajax, каждый из которых занимает около 200 миллисекунд для выполнения, и мне нужно дождаться завершения их ВСЕ, прежде чем выполнять действие (рисование графика).javascript - Передача аргументов объекта setInterval

Мое решение состояло в том, чтобы каждый поток приращивал глобальную переменную, когда закончил. Затем я создал таймер, используя setTimeout, чтобы проверять каждые 100 миллисекунд, чтобы увидеть, обновили ли все потоки переменную, и если они были, для выполнения действия.

Несмотря на то, что он немного взломан, это сработало.

Быстрая перемотка вперед на несколько недель в будущее, и моя программа растет, и теперь нам нужно быть , способным иметь несколько графиков на одной странице, каждый из которых управляет своими данными независимо, используя вышеупомянутые запросы ajax, так как а также несколько страниц, которые используют графики. Поэтому я извлекаю код графического кода в модуль с require.js и определяю класс, который выполняет графическое отображение, чтобы изолировать каждый граф от других, но внезапно setInterval не работает. Я сделать некоторые Googling и найти в следующей статье, которую я вроде понимаю ...

http://www.novogeek.com/post/2010/02/08/Scope-problems-with-JavaScript-setInterval-setTimeout-Use-closures!.aspx

Так или иначе, кажется, что «это» становится окно для какой-то странной причине, когда используется setInterval, и поэтому его не вижу моих методов.

В любом случае, я попытался создать var inst, чтобы содержать это «явно», что, казалось, помогло, но по какой-то причине ему не нравится передавать «inst» в качестве аргумента в рекурсивном вызове. Сообщение об ошибке из консоли Firebug это:

отсутствует] после того, как список элементов [Перерыв на этой ошибке]
} (9,9, [объект Object]))

Вот пример из мой код:

var inst = this; 

// some code... then in a function... 
function(){ 
    inst.waitUntil(10, inst); 
} 

inst.waitUntil = function(how_many_seconds, inst){ 
    if (how_many_seconds < 0){ 
     alert("Script timed out."); 
     return; 
    } else { 
     if (inst.allSchoolsLoaded()){ 
      setTimeout("("+inst.draw+"("+inst.after+"))", 100); 
     } else { 
      var argString = "("+inst.waitUntil+"("+(how_many_seconds-0.1)+", "+inst+"))"; 
      //alert(argString); 
      setTimeout(argString, 100); 
     } 
    } 
} 

Вы можете предположить, что все указанные выше переменные определены ранее в классе.

Я нахожусь на своем конце, любая помощь будет действительно оценена. Если кто-то может предложить лучшее решение проблемы с потоками, которая полностью исключает setInterval, это было бы потрясающе, в противном случае, если вы можете предложить способ заставить setInterval работать или альтернативную функцию, которая тоже будет отличной.

Доступен jQuery, и я не против установки других инструментов, если они помогут.

Большое спасибо заранее,

Alex

+0

Так что же случилось с 'вар completedCalls = 0; function ajaxThreadResult() {... completedCalls ++; } ', а затем проверить, если' finishedCalls == callsMade'? –

+0

см. Этот вопрос и ответов там: http://stackoverflow.com/questions/2130241/pass-correct-this-context-to-settimeout-callback/9298306#9298306 –

+0

Да, это на самом деле то, что я делаю ... . function allSchoolsLoaded() просто проверяет завершенныеCalls == callsMade (с разными именами переменных, очевидно). Проблема заключалась в том, как проверить этот статус с интервалами ... – Alex

ответ

3

Вы пытаетесь создать строку с объектом. Стандартное строковое представление объекта - [object Object]. Вероятно, у вас также будут проблемы с inst.waitUntil, так как он преобразуется в строковое представление функции (которая является источником функции в некоторых (большинство?) Браузерах).

Вместо создания строки, просто передать функцию setTimeout:

setTimeout(function() { 
    inst.waitUntil(how_many_seconds-0.1, inst); 
}, 100); 

Теперь внутри waitUntil, this будет относиться к inst. Учитывая это, вы, возможно, сможете упростить свой код.

Например:

this.waitUntil = function(how_many_seconds){ 
    var self = this; 
    if (how_many_seconds < 0){ 
     alert("Script timed out."); 
     return; 
    } else { 
     var callback = function() { 
      self.waitUntil(how_many_seconds-0.1); 
     }; 

     if (this.allSchoolsLoaded()){ 
      callback = function() { 
       self.draw(self.after); 
      }; 
     } 
     setTimeout(callback, 100); 
    } 
}; 
+0

:-) Мы написали одно и то же, извините, но мне нравится иметь только один setTimeout больше, приятно! –

+0

Я помню, что искал примеры в Интернете для setTimeout, и по какой-то причине они не показали, что вы можете передать функцию, поэтому я совершил ту же ошибку, что и Алекс. Хотел бы я знать о переполнении стека, чтобы получить ответ, подобный этому. ;-) –

+0

Правильно, я думаю, я смутился и думал, что setInterval всегда устанавливает это «в окно» ... Большое спасибо за вашу помощь :) – Alex

1

Не используйте строку, он использует eval внутренне, и это плохо сказывается на производительности и надежность вашего кода. Вместо этого:

if (inst.allSchoolsLoaded()){ 
    setTimeout("("+inst.draw+"("+inst.after+"))", 100); 
} else { 
    var argString = "("+inst.waitUntil+"("+(how_many_seconds-0.1)+", "+inst+"))"; 
    //alert(argString); 
    setTimeout(argString, 100); 
} 

ли это:

if (inst.allSchoolsLoaded()){ 
    setTimeout(function() { 
     inst.draw(inst.after); 
    }, 100); 
} else { 
    setTimeout(function() { 
     inst.waitUntil(how_many_seconds - 0.1); 
    }, 100); 
} 

Кроме того, вам не нужно проходить inst, если вы используете метод waitUntil на например, this контекст будет установлен inst себя, так :

inst.waitUntil = function (seconds) { 
    // `this` is now pointing at `inst` 
    // we will cache a reference to the object into a variable 
    // because anonymous function will have its own context (`this`) 
    // in the link provided in comment you can see alternatives such as using 
    // ECMAScript `bind` Function method to bind function context to certain object 
    var self = this; 
    if (seconds < 0) return alert('timeout'); 
    if (inst.allSchoolsLoaded()){ 
     setTimeout(function() { 
      self.draw(self.after); 
     }, 100); 
    } else { 
     setTimeout(function() { 
      self.waitUntil(seconds - 0.1); 
     }, 100); 
    } 
}; 
+0

Спасибо за помощь :) – Alex

0

Решения, размещенные здесь, отлично работают, спасибо за помощь.

В случае, если кто-то имеет такую ​​же необходимость выполнять несколько запросов AJAX, я на самом деле наткнулся на метод JQuery ручки это элегантно:

http://api.jquery.com/jQuery.when/

Это может занять несколько «Отложенный» объекты, в том числе Ajax запросов и ожидает, что все они будут успешно выполнены или один из них завершит сбой. Используя это, я могу полностью избавиться от таймера setInterval.

Cheers,

Alex