Страницы: 1
Быстрая демонстрация
Синхронный код. Простой и лаконичный, но, пока он не завершится полностью, другие задачи не исполняются.
let downloadSync= function( from, to ){ try { let content= getContent( from ) writeContent( to, content ) alert( 'saved!' ) } catch( e ){ console.error( e ) } }
Асинхронный код. Пока идёт ожадание окончания запросов можно сделать ещё много других полезных вещей. Но структура кода трудна для восприятия так как представляет из себя хитрое переплетение функций.
let downloadAsync= function( from, to ){ getContent( from, whenContentReceived, onError ) function whenContentReceived( content ){ writeContent( to, content, whenContentWrited, onError ) } function whenContentWrited( ){ alert( 'saved!' ) } function onError( e ){ console.log( e ) } }
Цепочечный код. С помощью специального хелпера все функции и асинхронного варианта выстраиваются в одну линию. Обилие синтаксического шума и несовместимость со стандартными операторами управления потоком исполнения.
let downloadChain= function( from, to ){ Chain ( function( ){ return getContent( from ) } , function( content ){ return writeContent( to, content ) } , function( ){ alert( 'saved!' ) } ).fail( function( e ){ console.log( e ) } ).run() }
Волокнистый код. Не останавливает исполнение других задач, но в то же время сохраняет линейную стуктуру подобно синхронному коду, почти не усложняя синтаксис.
let downloadFiber= FiberCallback( function( from, to ){ try { let content= yield getContent( from ) yield writeContent( to, content ) alert( 'saved!' ) } catch( e ){ console.error( e ) } } )
Подробнее о реализации
Сперва немного терминов..
Волокно - функция, имеющая следующий интерфейс:
* на вход она принимает 2 колбэка. первый должен быть вызван в случае успеха, единственным параметром ему передаётся вычисенный результат. второй вызывается в случае каких-либо ошибок, параметром ему передаётся объект исключения.
* колбэк должен быть вызван ровно один и ровно один раз
* она не должна выбрасывать никаких исключений - все ошибки должны приводить к выполнению второго колбэка
Простейшее волокно выглядит, например, так:
let Confirm= function( done, fail ){ try { let choice= confirm( 'Are you ready?' ) done( choice ) } catch( exception ){ fail( exception ) } }
Чтобы не писать каждый раз эти типовые try-catch, можно воспользоваться специальным хелпером:
let Confirm= $fenix.Fiber( function( done, fail ){ let choice= confirm( 'Are you ready?' ) done( choice ) } )
Что если нам нужно, чтобы волокно могло принимать какие-то дополнительные параметры? Для этого можно воспользоваться замыканиями:
let Confirm= function( message ){ return $fenix.Fiber( function( done, fail ){ let choice= confirm( message ) done( choice ) } ) }
Теперь Confirm - уже не само волокно, а фабрика волокон. Но постойте, код получился уж слишком сложным. Аналогичная безволоконная функция выглядит сильно проще:
Для упрощения создания волокон есть волшебный хелпер, преобразующий обычную функцию в фабрику волокон:
let Confirm= $fenix.FiberThread( function( message ){ let choice= confirm( message ) return choice } )
Но волшебство её не в этом, а в том, что она может приостанавливать своё исполнение в любой момент в ожидании завершения асинхронного вызова:
let AskUser= $fenix.FiberThread( function( message ){ let choice= yield Confirm( message ) alert( 'Your choice is ' + choice ) } )
Чтобы приостановить исполнение нужно воспользоваться оператором yield, которому передать волокно (в примере оно создано фабрикой Confirm). Ввиду такого хитросплетения волокон такая функция и названа нитью. В данном случае реализация Confirm у нас синхронна, но ничто не мешает ей быть и асинхронной:
let Confirm= function( message ){ return $fenix.Fiber( function( done, fail ){ formConfirm.elements.question.value= message formConfirm.elements.yes.onclick= formConfirm.elements.no.onclick= function( event ){ try { let choice= ( event.target.value == true ) done( choice ) } catch( exception ){ fail( exception ) } } } ) }
И опять эти try-catch для обеспечения интерфейса волокон. Для упрощения работы с колбэками, служит специальный хелпер:
let Confirm= $fenix.FiberThread( function( message ){ let result= $fenix.FiberTrigger() formConfirm.elements.question.value= message formConfirm.elements.yes.onclick= result.done formConfirm.elements.no.onclick= result.done let[ event ]= yield result yield $fenix.FiberValue( event.target.value ) } )
Триггер - это волокно, предоставляющее 2 ручки - done и fail. Достаточно передать метод done в качестве колбэка, и с помощью yield подождать срабатывания триггера. В рузультате вы получите список аргументов переданных колбэку.
Важно отметить, что если внутри нити используется хотябы один yield, то интерпретатор не позволяет использовать return. Поэтому реализация FiberThread такова, что нить возвращает вызвавшему её коду результат последнего yield-а, а волокно FiberValue обеспечивает чтобы это было именно то значение, которое ему передали.
Но что если внутри волокна возникнет исключение? Например, мы забыли добавить в форму элемент question и не найдя его Confirm вывалился с исключением. В соответствии с интерфейсом волокон, будет вызван колбэк fail. Но, если волокно было вызвано с помощью yield из нити, то исключение можно перехватить стандартным способом:
let AskUser= $fenix.FiberThread( function( message ){ let choice try { choice= yield Confirm( message ) alert( 'Your choice is ' + choice ) } catch( exception ){ alert( 'Can not ask user for choice' ) } } )
Если же никто исключение не перехватит - оно вывалится в консоль вместе со стрек-трейсом.
Быстрый старт
Выкачиваем фреймворк (https://github.com/nin-jin/fenix) и кладём куда-нибудь к себе в расширение. В chrome.manifest добавляем ресурс:
Третьим значением тут идёт относительный путь к директории с фреймворком.
Теперь где угодно вы можете получить корень фреймворка:
А с его помощью и доступ к модулям fenix (тут можно использовать как абсолютный путь, так и относительный):
Хотя корень и модули fenix лежат рядом, не стоит подключать модули так:
ибо если фреймворк будет используется несколькими расширениями, то вы не сможете быть уверенными, что модули берутся из вашей версии феникса.
Отредактировано tenshi (17-10-2011 10:25:20)
Отсутствует
Страницы: 1