2016-07-13 3 views
2

Я хочу запускать функцию один раз в секунду, а сама функция занимает 3 секунды. результаты в том, что каждый интервал выполняется при разности <function execution time>*2+<setInterval delay>setInterval странное поведение в nodejs

Я написал следующий код:

var seconds = 3; 

setInterval(
    function(){ 
      console.info(new Date().toString()); 
      var waitTill = new Date(new Date().getTime() + seconds * 1000); 
      while(waitTill > new Date()){} 
    },1000 
); 

и каждая итерация как я указано в формуле:

Wed Jul 13 2016 09:49:07 GMT+0300 (IDT) 
Wed Jul 13 2016 09:49:14 GMT+0300 (IDT) 
Wed Jul 13 2016 09:49:21 GMT+0300 (IDT) 
Wed Jul 13 2016 09:49:28 GMT+0300 (IDT) 

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

Что происходит?

вся информация, касающаяся этой проблемы, была бы весьма признательна.

спасибо!

использованием Nodejs 6.3.0

обновление

попробовал этот код в браузере Google Chrome ... ... здесь интервал выполняется каждые 3 секунды, который до сих пор странно.

обновление

спасибо за все ваши комментарии, одна последняя вещь, что не ясно. Почему в NodeJS, когда у меня установлено значение SetInterval() на 1 секунду, и выполнение функции занимает 3 секунды, почему следующее выполнение составляет 7 секунд вместо 4 секунд или даже 3 секунды. для меня это действительно странное поведение. что приемлемое поведение?

+0

@Andreas: NodeJS однопоточный; JavaScript - это * не *. –

ответ

4

документации не указывается такое поведение

NodeJS-х documentation for setInterval характерно не указывает практически ничего о своем поведении, кроме того, что он будет повторять эту задачу.

результаты, которые я думал, что будет в том, что каждая итерация будет выполняться через 1 секунду независимо от того, сколько времени выполнения функции интервала принимает

Если вы имеете в виду, вы могли бы перекрывающихся казни, вы не можете в NodeJS; он запускает ваш код в одном потоке.

Если вы хотите, чтобы каждая итерация выполнялась через секунду после последнего завершения, это не так, как традиционно работает setInterval. У setInterval традиционно было по крайней мере два разных поведения в зависимости от того, какую реализацию вы использовали: планирование следующей итерации в начале текущего текущего или планирование его на конец текущего. И это только в браузерах. Это с been standardized for browsers, но NodeJS не является браузером и не требуется работать одинаково. (И на самом деле это не по-другому: в браузерах требуется вернуть номер setInterval, а в NodeJS он возвращает объект.) Помните, что таймеры не являются особенностью JavaScript, они являются функцией среды хоста.

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

Re правки:

почему в NodeJS, когда у меня есть setInterval() установлен на 1 секунду, а выполнение функции занимает 3 секунды, поэтому следующий исполнение 7 секунд вместо 4 секунд или даже 3 секунды. для меня это действительно странное поведение. что приемлемое поведение?

Да. Это странно и удивительно (на мой взгляд), но NodeJS определяет свое поведение для setInterval, поэтому приемлемо. В моих экспериментах (ниже), по-видимому, измеряется, как долго выполнялось предыдущее выполнение вашей функции, затем добавьте, чтобы длина таймера была равна lastExecutionLength + desiredInterval, прежде чем она снова заработает. Это явно не соответствует спецификации для браузеров, но опять же, NodeJS не является браузером.

Вот мой тестовый скрипт:

let counter = 0; 
let timeAtEndOfLastExecution = 0; 
let timer = null; 

function log(msg) { 
    console.log(Date.now() + ": " + msg); 
} 

function tick() { 
    let start = Date.now(); 
    if (timeAtEndOfLastExecution) { 
     log("tick (" + (Date.now() - timeAtEndOfLastExecution) + "ms)"); 
    } else { 
     log("tick"); 
    } 
    if (++counter == 10) { 
     clearInterval(timer); 
    } else { 
     let wait = 200 + (Math.floor(8 * Math.random()) * 100); 
     log("waiting " + wait + "ms"); 
     let stopWaiting = Date.now() + wait; 
     while (Date.now() < stopWaiting) { 
      // busy wait 
     } 
     log("exiting callback after " + (Date.now() - start) + "ms"); 
     timeAtEndOfLastExecution = Date.now(); 
    } 
} 
timer = setInterval(tick, 200); 

И пробег образец (с узлом v6.2.2):

 
1468396730618: tick 
1468396730619: waiting 400ms 
1468396731020: exiting callback after 416ms 
1468396731637: tick (617ms) 
1468396731637: waiting 500ms 
1468396732137: exiting callback after 500ms 
1468396732837: tick (700ms) 
1468396732837: waiting 900ms 
1468396733737: exiting callback after 900ms 
1468396734837: tick (1100ms) 
1468396734837: waiting 300ms 
1468396735137: exiting callback after 300ms 
1468396735637: tick (500ms) 
1468396735637: waiting 700ms 
1468396736337: exiting callback after 700ms 
1468396737237: tick (900ms) 
1468396737237: waiting 800ms 
1468396738037: exiting callback after 800ms 
1468396739036: tick (999ms) 
1468396739036: waiting 900ms 
1468396739936: exiting callback after 900ms 
1468396741036: tick (1100ms) 
1468396741036: waiting 700ms 
1468396741736: exiting callback after 700ms 
1468396742636: tick (900ms) 
1468396742636: waiting 200ms 
1468396742836: exiting callback after 200ms 
1468396743236: tick (400ms) 

Как мы видим, он постоянно ждет длину предыдущей итерации плюс интервал, который я дал:

  • Первый обратный вызов занял в общей сложности 416 мс; следующий начался 617 мс после его возвращения
  • Второй обратный вызов занял 500 мс; следующий заработал 700 мс после его возвращения
  • Третий обратный вызов 900 мс; следующий запустил 1100 м после его возвращения
+0

Почему я получаю разные результаты между nodejs и браузером? и почему nodejs снова ожидает время выполнения, а затем задержка и только затем выполняет следующую итерацию? – ufk

+1

@ufk: NodeJS и браузеры - это разные среды; помните, что 'setInterval' не является частью JavaScript, это особенность среды, в которой работает ваш код. Точный способ работы 'setInterval' (теперь) [указан для браузеров] (https://www.w3.org/TR/html5/webappapis.html#timer-initialization-steps), но NodeJS не требуется для работают одинаково. –

+0

ok .. спасибо за все. мне просто не ясно. обновление основного сообщения – ufk

Смежные вопросы