В продолжение
поста про
конечные автоматы в яваскрипт.
Поскольку мне
не подошла готовая библиотека, реализующая
подход FSM, я решил делать свой вариант
реализации. Простой, ничего лишнего,
без блекджека-и-шлюх. В моем варианте
реакция на событие определяется
однозначно через текущее состояние и
само событие. Фактически, строка
«currentState_eventName» дает ссылку на функцию
для исполнения.
Законченный
пример (без HTML кода):
$(document).ready(onDocReady());
function onDocReady() {
try {
$(document).stopTime('doWork');
$(document).everyTime(999, 'doWork', onTimerWork);
} catch(ex) {
console.log('Error in function onDocReady: ' + ex.description, true);
}
} // function onDocReady()
function onTimerWork(i) { // work cycle
try {
// app ready?
if (VSClient.isBusy) return;
if (VSClient.currentState == '') {
VSClient.configure();
return;
}
VSClient.procEvent('timer');
} catch(ex) {
$(document).stopTime('doWork');
VSClient.procEvent('error');
log('Error in function onTimerWork: ' + ex.description, true);
}
} // function onTimerWork(i)
function onSelectFile() { // onClick button 'SelectFile...'
try {
VSClient.procEvent('selectFile');
} catch (ex) {
log('Error in function onSelectFile: ' + ex.description, true);
VSClient.procEvent('error');
}
return true;
} // function onSelectFile()
VSClient = { // Object with app data
sl: '' // Silverlight object
, isBusy: false
, fsmTable: [
{ from: '', event: 'configure', to: 'ready', action: 'configure' }
, { from: 'ready', event: 'selectFile', to: 'wait4FileName', action: 'selectFile' }
, { from: 'wait4FileName', event: 'timer', to: 'haveFileName', action: 'getFileName' }
, { from: '*', event: 'error', to: 'error', action: 'stopOnError' }
]
, currentState: ''
, fsmArray: {}
, configure: function() { // on page loaded, init app data
log('VSClient.configure');
this.isBusy = false;
this.sl = $('#silverlightObject')[0].content.vcuSL;
this.currentState = 'ready';
for(var n = 0; n < this.fsmTable.length; n++) {
var itm = this.fsmTable[n];
this.fsmArray[itm.from + '_' + itm.event] = itm;
}
try {
var res = this.sl.procMessage('test', '');
} catch (ex) {
this.sl = '';
this.currentState = '';
}
log('VSClient curr.state: ' + this.currentState);
} // configure: function(){}
}; // VSClient
VSClient.procEvent = function(evt) {
var llog = log;
if (evt == 'timer') llog = function(){;}
var ind = this.currentState + '_' + evt;
var itm = this.fsmArray[ind] || this.fsmArray['*_' + evt] || '';
if (itm == '') {
llog('VSClient.procEvent, no such transition: ' + ind);
return;
}
llog('VSClient.procEvent, tableIndex: ' + ind);
this.currentState = itm.to;
llog('VSClient curr.state: ' + this.currentState);
if (itm.action == '') {}
else {
this[itm.action].call(this);
}
} // VSClient.procEvent = function(evt)
// { from: 'ready', event: 'selectFile', to: 'wait4FileName', action: this.selectFile }
VSClient.selectFile = function() { // fsm action
log('VSClient.selectFile');
var res = this.sl.procMessage('selectFile', '');
if(res == '' || res.indexOf('fail') == 0) {
// error
log('VSClient.selectFile, error: ' + res, true);
} else {
// wait for SL, user must pick the file
$('#inpFileName').val('');
}
} // VSClient.selectFile = function()
// { from: 'wait4FileName', event: 'timer', to: 'haveFileName', action: this.getFileName }
VSClient.getFileName = function() { // fsm action
// check if user pick the file
var res = VSClient.sl.procMessage('selectFile', 'getName');
if(res == '') {
// file not selected
this.currentState = 'wait4FileName';
return;
}
log('VSClient.getFileName, res: [' + res + ']');
log('VSClient curr.state: ' + this.currentState);
$('#inpFileName').val(res);
} // VSClient.getFileName = function()
// { from: '*', event: 'error', to: 'error', action: this.stopOnError }
VSClient.stopOnError = function() { // fsm action
log('VSClient.stopOnError');
} // VSClient.stopOnError = function()
|
По сравнению
с тем, что было (нагромождение if-else), как
небо и земля. Теперь код понятнее изрядно.
Вообще, это я
все терзаю задачу «resumable
http chunked file upload». Просто эталонная
задача для прокачки скиллов. Вот, к
примеру, на хабре попалось:
Если вы
когда-либо загружали видеофайл на сайт,
то знаете это чувство когда загрузилось
90% и вы случайно обновляете страницу.
В этом учебном
руководстве я покажу, как сделать видео
загрузчик для сайта, который может
возобновить прерванную загрузку, и
генерировать обложку после завершения.
...
Чтобы сделать
этот загрузчик, сервер должен отслеживать
процесс загрузки, что бы была возможность
восстановить его при обрыве. Чтобы
выполнить эту задачу... с помощью
Node.js...
мы будем
использовать Socket.io...
Это перевод
вот этой статьи.
Ужасный перевод, но суть уловить можно.
Как совершенно верно заметили в каментах:
Стрёмный
перевод.
Но есть два
полезных момента в статье: из неё вы
узнаете, что Socket.io (посредством WebSocket)
умеет передавать двоичные данные, и что
файл на клиенте можно разбивать на куски
с помощью slice api.
Пойду, попробую
решить задачу возобновляемой отгрузки
файлов на связке HTML5 FileAPI + Node.js + Socket.io
Надо же
проверить, где грабли лежат. А вдруг
многогигабайтные файлы невозможно
обработать? Или — а нахрена тут Node.js,
что, без него нельзя?
Комментариев нет:
Отправить комментарий