Немного О Java Script В Клиенте (не Web)

Тема в разделе "Lotus - Программирование", создана пользователем alexas1, 17 сен 2014.

  1. alexas1

    alexas1 Lotus team
    Lotus team

    Регистрация:
    10 апр 2014
    Сообщения:
    567
    Симпатии:
    214
    Обычно, JS в клиенте игнорируют. А зря.
    Вот пример добавление на форму, практически, "дополнительного" onChange Event для произвольного количества обычных полей ввода, который позволяет очень просто работать с вводимыми данными OnFly.
    Просто добавить маленький код в JS Header и прописать в нём контролируемые поля.
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">JS Header</div></div><div class="sp-body"><div class="sp-content">
    Код (Text):
    var enterFields = ["field1", "field2", "field3"];
    var f = document.forms[0];
    //===============================================
    function checkField ()
    {
    try{
    for (i = 0; i < enterFields.length; ++i)    { //просматриваем все поля ввода из списка "enterFields"
    var tmpval = f[enterFields[i]].value.replace(/\./g,",") //замена точки на запятую
    tmpval = String(tmpval.match(/-?\d*\,?\d*\n?/)) //любое кол-во цифр
    // tmpval = String(tmpval.match(/-?\d?\d?\d?\d?,?\d?\d?\d?\n*/)) //макс. 7 цифр всего (макс. 3 знака после запятой)
    if(tmpval.indexOf("\n")!=-1)    { //если нажат ENTER
    if (tmpval.charAt(tmpval.length-2)==","){tmpval = tmpval.slice(0,-2)}   //удаляем запятую, если после неё ничего нет
    if(i < enterFields.length-1){f[enterFields[i+1]].focus()}; //переводим фокус на следующее поле если оно не последнее
    tmpval = tmpval.replace(/\n/g,""); //убираем перевод строки
    // f.MyButton.click();      //действия по ENTER-у кодом в "MyButton"
    }
    f[enterFields[i]].value = tmpval
    }
    }
    catch(e){}
    setTimeout('checkField ()', 100)   
    }
    checkField ()
    field1-field3 - поля в которые добавили "ивент".
    Пример на лету:
    заменяет точку на запятую (юзер не задумывается о правильности ввода числа),
    не даёт вводить ничего, кроме цифр и "минуса"
    не даёт вводить перевод строки (по Enter переходит на следующее поле ввода).

    Преимущества:
    весь код форматирования/проверки в одном месте,
    100% интерактив,
    доступны все прелести RegExp - произвольное форматирование введённого "на лету",
    просто дифференцировать нужные действия в полях с помощью switch case (в примере нет)

    Пока глюков замечено не было. Пара десятков контролируемых полей плюс десяток открытых доков с этим функционалом клиент не нагружают никак (client v9). Уменьшение Timeout до 1мс. ничего не рушило.
    =================================================
    P.S.
    Это просто иллюстрация техники.
    Не используйте этот код в боевой базе - утечка памяти!!!
    Ниже - код без бага.
     
  2. lmike

    lmike нет, пердело совершенство
    Команда форума Lotus team

    Регистрация:
    27 авг 2008
    Сообщения:
    6.082
    Симпатии:
    300
    код маньячит по доку, по таймеру, не внимая отсут. изменений в полях?
    может стоило закешировать содержимое и проверять на отсут. изменений...
     
  3. erdi

    erdi Well-Known Member

    Регистрация:
    20 авг 2008
    Сообщения:
    261
    Симпатии:
    36
    JS в клиенте стараюсь использовать во временных(диалоговых) формах, т.к. если курсор будет находится долгое время(от 15-40 минут по разному бывало) в поле на форме, которую забудет закрыть пользователь, то тогда в клиенте вылетает ошибка JS и клиент начинает вообще чудить, игнорируя даже код на LS. Помогает только перегрузка клиента.

    Для постоянной формы(у меня такая стартовая страница и на ней есть поле поиска сотрудников) я специально дополнил эту функцию счетчиком, которая делает итерацию при каждом вызове функции checkField () и если достигнут предел, то обнуляет счетчик и убирает фокус с этого поля, чтобы JS код больше не выполнялся
     
  4. garrick

    garrick Lotus team
    Lotus team

    Регистрация:
    26 окт 2009
    Сообщения:
    773
    Симпатии:
    52
    Ну, раз пошла такая пьянка, то и про CSS напиши что-нибудь.
     
  5. savl

    savl Lotus team
    Lotus team

    Регистрация:
    28 окт 2011
    Сообщения:
    2.052
    Симпатии:
    146
    garrick
    Не под web CSS можно использовать только для цвета в таблицах и глобально для формы цвет всех таблиц.
    Игрался тут, пытался сделать разный шрифт - не работает :D
     
  6. alexas1

    alexas1 Lotus team
    Lotus team

    Регистрация:
    10 апр 2014
    Сообщения:
    567
    Симпатии:
    214
    Это утечка памяти.
    100% у Вас в коде есть "замыкания", которые и приводят к утечкам. Это не проблема нотуса - это особенности JS.
    Менеджер памяти в нотусах не работает полностью в RealTime - он чистит память с периодичностью примерно 30 минут.
    Если утечки забили память до 50 Мб (примерно), а нотус не успел её освободить, клиент упадёт.
    Что у Вас и происходит.
    setInterval/setTimeout однозначно создают утечки:
    при передаче функции в setInterval/setTimeout создаётся внутренняя ссылка на неё, через которую клиент(браузер) её будет запускать. Поэтому функция остаётся жить, даже если других ссылок на неё нет.
    Для setTimeout — внутренняя ссылка должна исчезнуть после исполнения функции.
    Для setInterval — ссылка должна исчезнуть при очистке таймера.
    Но нотус НЕ ДЕЛАЕТ этого RealTime! Надо озаботиться этим самому.
    Для setTimeout я нашёл решение проблемы в нотусах - необходимо чистить объект setTimeout перед каждым запуском. Причём делать это надо не там, где описана вызываемая функция, а, например, в коде кнопки (ХЗ, почему так :angry2: )
    Для кода, который я предложил, чтобы полностью устранить утечки памяти, надо заменить setTimeout('checkField ()', 100) на f.repeatFunction.click()
    А в кнопе, с HTML Name = repeatFunction, поместить скрипт:
    Код (Text):
    clearTimeout(timeoutID)
    delete timeoutID
    timeoutID = setTimeout('checkField()', 100)
    И, конечно, определить timeoutID, как глобальную переменную var timeoutID
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Скрипт БЕЗ утечек памяти</div></div><div class="sp-body"><div class="sp-content">
    Код (Text):
    var enterFields = ["field1", "field2", "field3"];
    var f = document.forms[0];
    var timeoutID;
    //===============================================
    function checkField ()
    {
    try{
    for (i = 0; i < enterFields.length; ++i)    { //просматриваем все поля ввода из списка "enterFields"
    var tmpval = f[enterFields[i]].value.replace(/\./g,",") //замена точки на запятую
    tmpval = String(tmpval.match(/-?\d*\,?\d*\n?/)) //любое кол-во цифр
    // tmpval = String(tmpval.match(/-?\d?\d?\d?\d?,?\d?\d?\d?\n*/)) //макс. 7 цифр всего (макс. 3 знака после запятой)
    if(tmpval.indexOf("\n")!=-1)    { //если нажат ENTER
    if (tmpval.charAt(tmpval.length-2)==","){tmpval = tmpval.slice(0,-2)}   //удаляем запятую, если после неё ничего нет
    if(i < enterFields.length-1){f[enterFields[i+1]].focus()}; //переводим фокус на следующее поле если оно не последнее
    tmpval = tmpval.replace(/\n/g,""); //убираем перевод строки
    // f.MyButton.click();      //действия по ENTER-у кодом в "MyButton"
    }
    f[enterFields[i]].value = tmpval
    }
    }
    catch(e){}
    f.repeatFunction.click() //!!! Тут убираем утечку памяти !!!///
    }
    checkField ()
    Скрипт клиента не обрушит - утечек нет совсем. Проверьте. Для жёсткости, можете выставить Timeaut в 1 мс. :)
     
  7. alexas1

    alexas1 Lotus team
    Lotus team

    Регистрация:
    10 апр 2014
    Сообщения:
    567
    Симпатии:
    214
    Походу, это ничего не даст.
    Самые большие накладные расходы, это чтение инфы из полей.
    match и replace - выполняются мухой.
    А ограничивать чтение из дока только полем в котором находится курсор - это задействовать штатные ивенты.
    Прописывать ивенты у двух десятков полей - не comme il faut, от этого и хотелось уйти.
    Быстродействие современных компов позволяет иногда халатно относиться к производительности скрипта. :angry2:
     
  8. savl

    savl Lotus team
    Lotus team

    Регистрация:
    28 окт 2011
    Сообщения:
    2.052
    Симпатии:
    146
    Заблуждение.
    Если код перегружен, то даже самый быстрый комп будет тупить.
     
  9. alexas1

    alexas1 Lotus team
    Lotus team

    Регистрация:
    10 апр 2014
    Сообщения:
    567
    Симпатии:
    214
    Ключевое слово было - "иногда".
    Я говорю об этом конкретном скрипте. А вообще, на производительность ВСЕГДА обращаю внимание.
    К тому же он возник у меня случайно, в процессе обучения товарища и об оптимизации не думал.
    Хотя, на вскидку, наверное, попробую использовать.
    На моём Core 2 Duo 2.00 GHz нагрузка на проц - 8% (20 контролируемых полей с периодом 100 мс.) хороший вариант.
    Сам скрипт жрёт всего 300 кб оперативки.
    Утечки памяти нет.
     
  10. garrick

    garrick Lotus team
    Lotus team

    Регистрация:
    26 окт 2009
    Сообщения:
    773
    Симпатии:
    52
    Это конечно "да", но тема сисек CSS осталась нераскрытой. :)
    И, кстати, если таблицы Read Only, то можно их в виде HTML, с тем же CSS, положить в Computed Text. Можно сделать очень красиво.
    А если у вас вся форма в таблице?
     
  11. alexas1

    alexas1 Lotus team
    Lotus team

    Регистрация:
    10 апр 2014
    Сообщения:
    567
    Симпатии:
    214
    С CSS я Вам уже не помогу - лень ковыряться :angry2:.
    Сам стал писать хепаги, а там проблем в клиенте с CSS нет (ну, почти нет :) )
    Хотя всякие интерфейсные фишки в классике иногда всплывают - в доработке старья. (вот как сейчас)
     
  12. savl

    savl Lotus team
    Lotus team

    Регистрация:
    28 окт 2011
    Сообщения:
    2.052
    Симпатии:
    146
    Если глобальный класс на всю форму и на все таблицы - то очень весело...
     
  13. savl

    savl Lotus team
    Lotus team

    Регистрация:
    28 окт 2011
    Сообщения:
    2.052
    Симпатии:
    146
    Код (C++):
    window.setInterval("runRefreshWindow();", 100);
    тоже создаст утечку памяти?
     
  14. alexas1

    alexas1 Lotus team
    Lotus team

    Регистрация:
    10 апр 2014
    Сообщения:
    567
    Симпатии:
    214
    Не однозначный вопрос.
    Надо уточнить откуда запускается setInterval и как устроена функция runRefreshWindow() ?
     
  15. savl

    savl Lotus team
    Lotus team

    Регистрация:
    28 окт 2011
    Сообщения:
    2.052
    Симпатии:
    146
    JS Header
    Код (C++):
    function runRefreshWindow()
    {
    var nr = "";
    nr = window.document.forms[0].ndRefresh.value;
    if (nr == "1") {window.document.forms[0].btnRefresh.click()}
    }
    onLoad
    Код (C++):
    window.setInterval("runRefreshWindow();", 100);
    Кнопка:
    Код (LotusScript):
    Sub Click(Source As Button)
    If currUIDoc.EditMode Then
    Call currDoc.ReplaceItemValue("ndRefresh","0")
    Call currUIDoc.Refresh
    End If
    End Sub
    currDoc и currUIDoc - глобальные объекты формы, получены в postOpen

    Добавлено: Поколбалисо форум =)
    Я не силен в JS, поэтому если можно улучшить, чтобы клиент вдруг не падал или что еще - буду благодарен.
     
  16. ty3uk

    ty3uk Well-Known Member

    Регистрация:
    31 мар 2008
    Сообщения:
    169
    Симпатии:
    0
    я не помню поборол-ли я этот момент, но, вроде, поставил какой-то счётчик, и при подходе счётчика к топовым значениям, перезапускаю проверку.
    Вот не помню, сделал-ли я такое, и помогло-ли. Но, думаю, идея понятна.
    А, блин, выше-же описан данный вариант....
     
  17. alexas1

    alexas1 Lotus team
    Lotus team

    Регистрация:
    10 апр 2014
    Сообщения:
    567
    Симпатии:
    214
    Сорри, за молчок - отпуск.
    В нарисованном варианте, утечек не будет.
    Только есть одно но: если будет запущенно 2 или больше setInterval с периодом 100 - клиент выдаст ошибку компиляции JS (через некоторое время).
    Я бы сделал по-другому (из давней практики):
    JS Header - пустой.
    onLoad - setInterval('document.forms[0].btnRefresh.click()', 250) (на onLoad - потому, что при запуске из Header, кнопы на форме ещё нет)
    В кнопе:
    If currDoc.ndRefresh(0) = "1" Then
    currDoc.ndRefresh = "0"
    Call currUIDoc.Refresh
    End If

    Проверять EditMode смысла нет - на чтении ndRefresh просто не изменится.

    button.click выполняется шустро, нет смысла его запускать по условию - быстродействие не пострадает.
    Да и всю логику держать в одном месте наглядней (в кнопе)

    250мс позволит запустить 5 одновременных сетинтервалов без гемора.
    500 - соответственно 10 и тд.
    Ну, или запрещать интерфейсно запуск нескольких setInterval (если маленькое время цикла), что не айс.
    Тут проблема с возможным наложением обработки нотусом последовательного запуска функции из setInterval.

    P.S.
    Ещё момент, если скрипт в кнопе долгий, надо проверять выполнилась ли предыдущая итерация полностью.
    Для doc.Refresh (если форма сложная и пересчёт полей может занять ощутимое время) можно завести, для контроля, служебное computed поле в самом низу формы в котором значение изменяется при рефреше (ну и чистить его после проверки в кнопе)
     
  18. maliy

    maliy Well-Known Member

    Регистрация:
    20 мар 2007
    Сообщения:
    135
    Симпатии:
    1
    Пробую код в 6 посте. Код вставил в JS header формы.
    Но выдает Error: ToObjectError: f.repeatFunction has no properties.
    В чем проблема?
     
  19. alexas1

    alexas1 Lotus team
    Lotus team

    Регистрация:
    10 апр 2014
    Сообщения:
    567
    Симпатии:
    214
    а кнопка то с именем "repeatFunction" есть ли на форме??? )))
     
  20. maliy

    maliy Well-Known Member

    Регистрация:
    20 мар 2007
    Сообщения:
    135
    Симпатии:
    1
    Да, кнопка есть HTML- > Name - repeatFunction
    в ней код (Client, JavaScript):
    clearTimeout(timeoutID)
    delete timeoutID
    timeoutID = setTimeout('checkField()', 100)
     
Загрузка...

Поделиться этой страницей