Javascript.RU

Многопоточный яваскрипт

Яваскрипт - однопоточный язык программирования. однако, в нём есть поддержка отложенного выполнения, когда мы устанавливаем обработчик события timeout и выходим из программы.

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

Эта их особенность и позволяет реализовать многопоточность в текущих версиях яваскрипта.

  1. Можно выполнять долгие вычисления или анимацию, не вешая при этом пользовательский интерфейс.
  2. Следствие из (1) - у нас нет ограничения на время выполнения.
  3. Каждый процесс является "истинным объектом" с очередью сообщений, рабочим пространством и независимостью от работоспособности других объектов.

из-за особеностей реализации (через таймер) суммарное время вполнения программы может сильно замедлитья, ибо setTimeout приводит к ощутимой задержке между сообщениями. однако, благодаря этому, браузер успевает отреагировать на активность пользователя и произвести все перерасчёты, связанные с ДОМ-ом, что бывает необходимо в некоторых случаях (например - native selectors в ИЕ). также мы получаем возможность производить безболезненно тяжёлые вычисления (например, сортировку большой таблицы).

что ж, ближе к делу...

Function.prototype.process= function( state ){
    var process= function( ){
        var args= arguments;
        var self= arguments.callee;
        setTimeout( function( ){
            self.handler.apply( self, args );
        }, 0 )
    }
    for( var i in state ) process[ i ]= state[ i ];
    process.handler= this;
    return process;
}

суть его такова: любую функцию можно превратить в процесс, вызвав её метод process. в качестве параметра ему передаётся объект, полями которого инициируется процесс. фактически, процесс является декоратором для функции, реализующиим её отложенное выполнение.

var printer= function( data ){
    document.write( data + ' ' );
}
for( var i= 0; i<100; i++ ){
    printer( i );
    document.write( '| ' );
}

Если выполнить этот код, то будут выведены числа от 0 до 99, разделённые вертикальной чертой. то есть, выполнение нашего кода приостанавливается на время выполнения функции print.

Однако, если мы декорируем эту функцию с помощью метода process:

printer= printer.process();
for( var i= 0; i<100; i++ ){
    printer( i );
    document.write( '| ' );
}

, то будет выведена сначала сотня вертикальных черт, а потом уже сотня чисел. то есть, мы передали функции сообщение и не дожидаясь завершения её выполнения, работаем дальше.

но далеко не всегда нужно полностью выйти из режима выполнения полностью - зачастую требуется временно приостановить выполнение с целью последующего возобновления с того же места. для этих целей есть смысл ввести такие понятия, как "состояние процесса" и "передача сообщений". и поможет нам в реализации всего этого замечательная конструкция switch-case:

var business= function( input ){
    switch( input.message ){
        case 'start':
            if( this.state !== 'wait' ) return this( input );
            this.body= document.getElementsByTagName( 'body' )[0];
            this.body.innerHTML+= '[business started] ';
            this.state= 'run';
            this.iteration= 0;
        case 'next':
            if( this.state !== 'run' ) return;
            this.body.innerHTML+= this.iteration + ' ';
            if( ++this.iteration < 100 ) return this({ message: 'next' });
        case 'finish':
            if( this.state !== 'run' ) return;
            this.body.innerHTML+= '[business stopped] ';
            this.state= 'wait';
        return;
    }
}.process({ state: 'wait' })

business({ message: 'start' });

мы создаём процесс, и инициируем его состояние строкой 'wait'. в этом режиме процесс висит и тупо ждёт комманды начать выполнение. как только к нему приходит комманда стартануть (последняя строчка), он инициализирует некоторые свои переменные ( body, iteration ), меняет состояние на 'run' и сразу переходит к выполнению первой итерации. внутри итерации выполняются некоторые действия и происходит проверка условия окончания цикла. если ещё не пора - повторяем итерацию, если пора - выполняем завершение процесса и переводим процесс в режим ожидания.

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

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

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

+2

Автор: Dmitry A. Soshnikov, дата: 25 апреля, 2008 - 23:48
#permalink

тоже далеко не новая идея, но полезная и интересная


Автор: Гость (не зарегистрирован), дата: 19 декабря, 2008 - 01:08
#permalink

не плохая статейка. помогло


Автор: hudson (не зарегистрирован), дата: 6 февраля, 2010 - 21:25
#permalink

Эм. Пример с применением конструктора процессов не работает. Выводит "0" и все. Что я делаю не так?


Автор: RUVATA, дата: 15 августа, 2011 - 10:31
#permalink

Где можно найти рефференс по методу "process" ?


Автор: Гость (не зарегистрирован), дата: 31 августа, 2011 - 13:07
#permalink

Код метода перед Вами.
Он не столь велик, чтобы для его освоения требовался отдельный мануал.


 
Поиск по сайту
Другие записи этого автора
tenshi
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Популярные таги
Последние темы на форуме
Forum