Каков случайный фактор в событии узла v10 l oop? - PullRequest
2 голосов
/ 06 мая 2020

Мой вопрос касается nodejs события l oop

Рассмотрим этот код

(async () => {
    let val = 1
    const promise = new Promise(async resolve => {
        resolve()
        await new Promise(async r => {
            setTimeout(r)
        })
        await promise
        val = 2
    })
    await promise
    await new Promise(resolve => setTimeout(resolve))
    console.log(val)
})()

С узлом 10.20.1 (последняя версия узла 10 )

for ((i = 0; i < 30; i++)); do /opt/node-v10.20.1-linux-x64/bin/node race-timeout.js; done

С узлом 12.0.0 (первая версия узла 12)

for ((i = 0; i < 30; i++)); do /opt/node-v12.0.0-linux-x64/bin/node race-timeout.js; done

Результат узла 10

1 2 2 1 1 2 2 1 2 1 1 1 1 1 2 1 1 2 1 2 1 1 2 2 1 2 1 1 2 1

Результат узла 12

2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2

До сих пор я знал, что node - это однопоточный язык. Все четко определено и выполняется в точном порядке, кроме случаев вмешательства на этапе опроса.

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

Каков случайный фактор в узле v10?

1 Ответ

1 голос
/ 06 июля 2020

Здесь все объяснено здесь .

Короче говоря, до v.11 вызов Promise.resolve().then( fn1 ); setTimeout( fn2, 0 ); мог привести к тому, что fn2 будет помещен в очередь таймеров, принадлежащих текущему событие l oop итерация, и, таким образом, fn2 сработает до того, как событие l oop даже войдет в очередь nextTicks (также известную как «очередь микрозадач»).

Согласно one комментарий здесь, несоответствие произошло из-за того, что « таймеры могли быть установлены на разные миллисекунды и, таким образом, истекли с интервалом в 1 мс », тем самым подталкивая fn2 к следующему событию l oop итерация и оставив очередь nextTicks, обрабатываемую между ними.

Другими словами, v10 должен большую часть времени выводить 1, кроме случаев, когда основное задание вызывало setTimeout в следующие мс, например, если основное задание задание называлось @ms 12.9, и что для перехода к вызову setTimeout потребовалось более 0,1 мс, то значение 0 setTimeout фактически будет соответствовать следующей очереди таймера (@ms 13), а не текущая (@ms 12).

В следующие версии * 102 6 *, nextTicks запускаются после каждых immediates и timers, поэтому мы уверены, что обратный вызов Promise будет выполнен сразу после задания, которое его выполнило, как в браузерах.

...