Статьи

Псевдопоточность на основе таймера JavaScript

В моем предыдущем посте « Выполнение JavaScript и ограничения браузеров» я описал, как 5 лучших браузеров определяют, когда код JavaScript выполняется слишком долго, и выдают ошибки «сценарий не отвечает». Изменять поведение браузера непрактично, и не всегда возможно перегрузить обработку на сервер. К счастью, таймеры могут помочь нам выполнять долгосрочные задачи без блокировки браузера.

Какие таймеры?

Код JavaScript, такой как отдельная функция, может быть запущен по истечении определенного периода времени:

  • setTimeout (функция, мсек [, arg1… argN])
    запускает названную функцию через миллисекунды мсек. Аргументы, если таковые имеются, передаются этой функции.
  • setInterval (функция, мсек [, arg1… argN])
    аналогично setTimeout, за исключением того, что функция вызывается бесконечно каждые миллисекунды мсек.

Две другие функции, clearTimeout() и clearInterval() , будут отменять операции таймера, например

 var timerID = setTimeout(myfunction, 500); clearTimeout(timerID); // myfunction() will never be called 

Замечания:

  1. setTimeout и setInterval передают ссылку на функцию (без скобок). Код setTimeout(myfunction(), 500); немедленно запустил бы myfunction ().
  2. Время миллисекунды редко будет точным. Они только указывают, что функция должна запускаться, когда браузер бездействует после определенного периода.
  3. Не полагайтесь на функции, выполняемые в определенном порядке, например, setTimeout(f1, 50); setTimeout(f2, 50); setTimeout(f1, 50); setTimeout(f2, 50); — f2 () может выполняться первым.

Выполнение по таймеру

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

В качестве простого примера предположим, что мы хотим запустить функции f1 (), f2 () и f3 () в следующем порядке:

 function ProcessThread(func) { var ms = 20; setTimeout(function() { func.shift()(); if (func) { setTimeout(arguments.callee, ms); } }, ms); } ProcessThread([f1, f2, f3]); 
примечание: func.shift () ()?!

Это требует небольшого дополнительного объяснения; func.shift () удаляет первый элемент из массива и возвращает его. Это будет ссылка на функцию, поэтому мы добавляем скобки для ее выполнения.

Оператор функционально идентичен var f = func.shift(); f(); var f = func.shift(); f();

ProcessThread запускает все функции в переданном массиве, но ожидает 20 мс между каждой. Любое количество функций может быть выполнено последовательно… при условии, что ни одна отдельная функция не выдаст ошибку «сценарий не отвечает».

Однако наиболее трудоемкий код, вероятно, будет обрабатывать большие массивы данных. В моем следующем посте мы напишем более надежный код для обработки операций такого типа.