2016-12-11 5 views
-1

Когда мы используем Promise в nodejs, учитывая Promise p, мы не можем знать, когда Promise p действительно разрешен путем регистрации текущего времени в обратном вызове «then».Как узнать, когда обещание фактически разрешено в Node.js?

Чтобы доказать, что я написал код теста (с использованием CoffeeScript):

# the procedure we want to profile 
getData = (arg) -> 
    new Promise (resolve) -> 
     setTimeout -> 
      resolve(arg + 1) 
     , 100 

# the main procedure 
main =() -> 
    beginTime = new Date() 
    console.log beginTime.toISOString() 
    getData(1).then (r) -> 
     resolveTime = new Date() 
     console.log resolveTime.toISOString() 
     console.log resolveTime - beginTime 
    cnt = 10**9 
    --cnt while cnt > 0 
    return cnt 

main() 

При запуске приведенный выше код, вы заметите, что resolveTime (время код запуска в функцию обратного вызова) намного позже, чем 100 мс от beginTime.

Итак, если мы хотим знать, когда обещание фактически разрешено, КАК?


Я хочу знать точное время, потому что я занимаюсь профилированием посредством регистрации. И я не могу изменить реализацию Promise p, когда занимаюсь профилированием вне черного ящика.

Итак, есть ли какая-то функция, такая как prom.onUnderatingConditionFulfilled (callback) или любой другой способ сделать это возможным?

+0

Почему вы хотите знать это время? – Bergi

+0

Фактическое! == предсказано. Без сюрпризов. –

+0

@ Bergi причина, я делаю некоторые профилирования через протоколирование, мне нужно знать, когда HTTP-запрос фактически отвечает, без влияния другого кода. – luochen1990

ответ

5

Это потому, что у вас напряженный цикл, который, по-видимому занимает больше времени, чем ваш таймер:

cnt = 10**9 
--cnt while cnt > 0 

Javascript в node.js однопоточны и события. Он может делать только одно за раз, и он завершит текущую работу, прежде чем он сможет обслуживать событие, отправленное setTimeout(). Таким образом, если ваш цикл занятости (или любой другой длинный фрагмент кода Javascript) занимает больше времени, чем вы установили для своего таймера, таймер не сможет работать до тех пор, пока этот другой код Javascript не будет выполнен. «single threaded» означает, что Javascript в node.js выполняет только одно за раз, и он ждет, пока одна вещь вернет управление обратно в систему, прежде чем он сможет обслуживать следующее событие, ожидающее запуска.

Итак, вот последовательность событий в коде:

  1. Он называет setTimeout() запланировать обратный вызов таймера для 100мса теперь.
  2. Затем вы зайдете в свою занятую петлю.
  3. Пока он находится в цикле занятости, таймер setTimeout() срабатывает внутри реализации JS и вставляет событие в очередь событий Javascript. Это событие не может работать в данный момент, потому что интерпретатор JS все еще работает с циклом занятости.
  4. Затем, в конце концов, он завершает цикл занятости и возвращает управление обратно в систему.
  5. Когда это будет сделано, интерпретатор JS затем проверяет очередь событий, чтобы узнать, нуждаются ли в обслуживании любые другие события. Он находит событие таймера, и поэтому он обрабатывает это и вызывается callback setTimeout().
  6. Этот обратный вызов разрешает обещание, которое вызывает обработчик .then() для вызова.

Примечание. Из-за однонаправленной и управляемой событиями Javascript таймеры в Javascript не могут быть вызваны именно тогда, когда вы их планируете. Они будут выполняться как можно ближе к ним, но если другой код работает в то время, когда они запускаются, или если у них много элементов в очереди событий впереди вас, этот код должен завершиться до того, как обратный вызов таймера фактически начнет выполняться.

Итак, если мы хотим знать, когда обещание фактически разрешено, КАК?

Обещание разрешается, когда выполняется цикл занятости. Это не разрешено точно в точке 100 мс (потому что ваш цикл занятости, по-видимому, занимает больше времени, чем 100 мс для запуска). Если вы хотите точно знать, когда обещание было разрешено, вы просто заходите в режим обратного вызова setTimeout(), где вы звоните resolve(). Это точно скажет вам, когда обещание было разрешено, хотя оно будет почти таким же, как и сейчас. Причиной вашей задержки является цикл занятости.


За ваши комментарии, кажется, что вы хотите как-то измерить точно, когда resolve() на самом деле называется в Promise, но вы говорите, что вы не можете изменить код в getData(). Вы не можете сделать это напрямую. Как вы уже знаете, вы можете измерить, когда вызывается обработчик .then(), который, вероятно, будет не более чем через пару мс после вызова resolve().

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

Итак, мне кажется, что вы только что сдерживали проблему. Вы хотите измерить, когда что-то внутри какого-либо кода происходит, но вы не допускаете каких-либо инструментов внутри этого кода. Это просто оставляет вас с двумя вариантами:

  1. Замените реализацию обещаний, чтобы вы могли непосредственно измерить прибор resolve().
  2. Измерение при срабатывании .then().

Первый вариант, вероятно, имеет проблему неопределенности в гейзенберге, поскольку вы, вероятно, повлияли на сроки больше, чем следует, если вы замените или примените реализацию обещания.

Второй вариант измеряет событие, которое происходит чуть позже фактического .resolve(). Выберите, какой из них наиболее близок к тому, что вы на самом деле хотите.

+0

... хотя, конечно, весь процесс обработки обратного вызова и обещания времени ожидания задерживается циклом занятости, а не только обратным вызовом обещания. Я ожидал бы <1ms между выполнением обратного вызова 'setTimeout' и обратным вызовом' then', поэтому перемещение 'resolveTime' там не должно иметь значения. – Bergi

+1

@ Bergi - Я не уверен, в какой именно момент вы пытаетесь это сделать. Я не пытался сказать, что была какая-то большая разница между тем, когда вызывается 'resolve()' и когда вызывается обработчик '.then()'. Я изменил последние два предложения, чтобы убедиться, что это ясно.Мой последний параграф просто пытался ответить на вопрос, который был задан. Все параграфы, которые приходят раньше, объясняют, почему это задерживается. – jfriend00

+0

Да, спасибо за разъяснение, что его перемещение вряд ли изменит поведение. – Bergi

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