Немедленно обновите элементы DOM в Javascript

#javascript #jquery

#javascript #jquery

Вопрос:

Для простого проекта я пытаюсь отобразить выходные данные журнала в текстовой области. У меня есть log функция, и я хотел бы, чтобы текстовая область всегда обновлялась немедленно при каждом log вызове. К сожалению, кажется, что обновление выполняется только один раз и одновременно загружает все (я использую jQuery для установки значения текстовой области, если это возможно имеет значение). Вот простой пример:

 for (i = 0; i <= 100; i  ) {
    $("textarea").html($("textarea").html()   "test"   i   "n");
    $("textarea").scrollTop(9999999)
};
  

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

 f = function(i) {
    if (i <= 100) {
        $("textarea").html($("textarea").html()   "test"   i   "n");
        $("textarea").scrollTop(999999);
        setTimeout(function() { f(i 1); }, 0);
    }
};

f(1);
  

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

Есть ли какой-либо способ добиться желаемого эффекта без обратных вызовов?

Комментарии:

1. Ну, ваш первый фрагмент настолько быстр, что кажется, что он добавляет текст сразу…

2. Чего именно вы пытаетесь достичь? Чем быстрее компьютер, тем меньше эффект будет заметен в любом случае. Я не совсем понимаю, зачем вам вся эта дополнительная перерисовка.

3. Ребята, я думаю, он хочет иметь возможность «видеть» все сообщения, которые приходят одно за другим (чтобы он мог видеть, что произошло по порядку) .. для этого он должен буферизировать зарегистрированное сообщение и периодически печатать.. смотрите мой ответ

4. Обратите внимание, что, поскольку вы используете тайм-аут, вызов на самом деле не является рекурсивным. 🙂

5. @Felix: В первом фрагменте он не добавляет их все сразу, потому что это быстро; вы можете увидеть, запустив второй фрагмент, что на самом деле отображение одной строки за раз выглядит по-другому. @pimvdb: Приложение представляет собой решатель судоку, который вычисляет список шагов, необходимых для решения судоку, а затем анимирует список шагов позже. Но я хотел бы регистрировать то, что происходит в решателе, по мере его вычисления. Кроме того, если решатель когда-либо выйдет из строя, в текстовую область ничего не выводится, что определенно является проблемой. @dwarfy: спасибо, это выглядит как отличное решение.

Ответ №1:

Я думаю, вы могли бы рассмотреть возможность использования :

 $("textarea").val(function(index, value) {
   return value   "test"   i   "n"
});
  

вместо :

 $("textarea").html($("textarea").html()   "test"   i   "n");
  

или вообще :

 $("textarea").val(NEWVAL)
  

Также отмечено в комментариях к вашему вопросу, если вы хотите иметь возможность замечать «на глаз» все поступающие сообщения, вам придется сохранять их в буфере и иметь что-то вроде (не тестировалось) :

 var buffer = []

function log(text) { buffer.push(text) }

setInterval(function(){
  if (len(buffer)>0) {
    $("textarea").val(function(index, value) {
      return value   "n"   buffer.shift()
    });
  }
},500)
  

Ответ №2:

Браузеры обычно (Opera является исключением) выполняют выполнение JS и рендеринг в одном потоке, поэтому, пока ваш JS запущен, рендеринг в браузере выполняться не будет, если вы явно не передадите управление с помощью тайм-аута или интервального таймера.