Отсутствие документированной функции в Espruino Web IDE

Тема в разделе "Iskra JS, Espruino, Йодо", создана пользователем FengRen, 12 июн 2016.

  1. FengRen

    FengRen Нуб

    На сайте http://wiki.amperka.ru/js:timer для модуля @amperka/timer указана функция Timer.interval([val],[units]). Но интерпретатор ее не находит, пишет "caught Error: Function "interval" not found!". При том, что функции Timer.create, Timer.run работают. На GitHub https://github.com/amperka/espruino-modcat/blob/master/modules/@amperka/timer.js данная функция тоже отсутствует. Где можно взять более новую библиотеку @amperka/timer?
     
  2. r1000ru

    r1000ru JS-технократ

    Здравствуйте. Действительно эта библиотека попала в продакшен без метода interval. Я его дописал и сейчас отправил библиотекуна код ревью, так что скоро будет доступна исправленная версия. Сейчас можете ее получить на GitHub в пулл-реквесте timer.

    Отдельно хочу добавить, что библиотека таймера - это просто обертка над функциями setInterval, changeInterval и clearInterval, по этому для реализации таймера ее использовать совершенно не обязательно. Для производительности лучше делать так:
    Код (Javascript):

    // Функция, выполняемая по таймеру
    var onTick = function() {
      LED1.write(!LED1.read());
    };

    // Запустим таймер
    var intId = setInterval(onTick, 1000);

    // Изменим период
    changeInterval(intId, 500);

    // Остановим таймер
    clearInterval(intId);
     
    Соответственно для изменения периода интервала и его остановки, необходимо знать его идентификатор, который возвращается при запуске интервала. Период указывается в миллисекундах (тысячных долях секунды).

    Иногда возникает ситуация, что необходимо остановить или изменить интервал, но его может не быть (был остановлен в каком-то другом месте и ID не обнулен). В таком случае стоит использовать конструкцию try {} catch {}. Она позволяет перехватывать ошибки и не останавливать выполнение программы:

    Код (Javascript):

    // Функция, выполняемая по таймеру
    var onTick = function() {
      LED1.write(!LED1.read());
    };

    // Запустим таймер
    var intId = setInterval(onTick, 1000);
    // Отобразим ID таймера
    print('IntID = ' + intId);
    // Попробуем удалить все таймеры с ID от 0 до 9
    for (i = 0; i<10; i++) {
      try {
        // Вызываем остановку таймера
        clearInterval(i);
      } catch (e) {
        // Если во время остановки произошла ошибка (таймер не существует)
        print ('Interval ID: ' + i + ' is not found');
      }
    }
     
    Т.е. в try вы берете функцию, которая может вызвать ошибку, а в catch - описываете действия, которые нужно совершить если ошибка произошла. Если нужно просто остановить интервал с определенным ID, то в catch можно ничего не писать. Таким образом программа продолжит свое выполнение и таймер гарантированно остановиться, если он существует.
     
  3. r1000ru

    r1000ru JS-технократ

    Исправленная версия библиотеки выгружена
     
  4. FengRen

    FengRen Нуб

    Спасибо за подробный ответ!!! Как раз необходимо изменять интервал вызова таймера)
     
    Последнее редактирование: 14 июн 2016
  5. FengRen

    FengRen Нуб

    На платформе mbed упоминается, что не рекомендуется помещать тяжелые операции в функцию таймера (циклы, передачу данных...). Так как, не законченное прерывание может обрываться новым. На платформе JS такое ограничение существует? или она чем-то похоже на RTOS?
     
  6. r1000ru

    r1000ru JS-технократ

    Ограничения те же самые, setInterval фактически задействует аппаратный таймер. С другой стороны если у вас передача данных - после срабатывания прерывания по приему (к примеру), программа вернется к выполнению текущего кода. А вот событии Serial.on('data') следует разбить строку на разделители, текущий обрабатываемый фрагмент записать в отдельную переменную, а оставшиеся не обработанные данные - немедленно дописать к буферу. И только после этого вызвать разбор принятых данных. Таким образом, если в процессе разбора придут новые данные - они просто будут добавлены к текущему буферу, а запущенный процесс обработки не прервется.
     
  7. acos

    acos Официальный гик Администратор

    Про serial - можно ссылочку на пример лучших практик?:)
     
    ИгорьК нравится это.
  8. FengRen

    FengRen Нуб

    Только начал все изучать. Можно изменять размер буфера? Или его размер константа?
     
  9. r1000ru

    r1000ru JS-технократ

    Переменную для буфера в JS вы создаете самостоятельно.
    Ниже пример, который обработает данные, передаваемые с задержкой, и с длительным временем обработки:
    Код (Javascript):
    // Настроим последовательный порт
    Serial3.setup(115200);

    // Буффер, где будут лежать полученные, но не обработанные данные;
    var buffer = '';

    // Разделитель данных, полученых по последовательному порту
    // В зависимости от передатчиков может быть разный по содержанию
    var delimiter = '\r\n';

    // Переменная, указывающая на то, что медленная функция в процессе работы
    var slowFuncIsWork = false;

    // Функция которая оооочень медленно обрабатывает команды
    var mySlowFunc = function(cmd) {
      slowFuncIsWork = true;

      // Медленное действие
      setTimeout(function() {
        // Через секунду отобразим параметр cmd
        print(cmd);
        // Как обработка закончилась - пометим, что ресурсы не заняты
        slowFuncIsWork = false;

        // Симулируем приход новых данных, чтобы проверить буфер, который может
        // их содержать не обработанными, а фактической передачи уже не будет
        Serial3.emit('data', '');
      }, 1000);
    };

    // На получение данных
    Serial3.on('data', function(data) {
      // Немедленно дописываем ими буфер
      buffer += data;

      // Если запущена обработка - прерываемся - выполним в следующий раз
      if (slowFuncIsWork) {
        return;
      }

      // Ищем в буфере разделитель
      var pos = buffer.indexOf(delimiter);

      // Если разделитель не найден - прерываемся, ждем дополнения данных
      if (pos < 0) {
        return;
      }

      // Сохраняем обрабатываемую команду
      var cmd = buffer.substr(0, pos);

      // Перед обработкой записываем в буфер остаток данных, которые
      // еще не обработаны. delimiter.length стоит заменить на число -
      // длину разделителя, так как его записывать в буфер мы не будем.
      buffer = buffer.substr(pos + delimiter.length);

      // Запускаем обработку
      mySlowFunc(cmd);
    });

    // Для тестирования симулируем прием данных частями с задержкой в 0.1 секунду
    Serial3.emit('data','Hello\r\nbra');
    setTimeout(function() {
      Serial3.emit('data', 've\r\nnew\r\nworld\r\n');
    }, 100);
     
    acos и ИгорьК нравится это.
  10. FengRen

    FengRen Нуб

    Спасибо! Пример очень помог!