Почему это так медленно?
Chrome (Мигание) на самом деле устанавливает минимальное время ожидания 4 мс :
// Chromium uses a minimum timer interval of 4ms. We'd like to go
// lower; however, there are poorly coded websites out there which do
// create CPU-spinning loops. Using 4ms prevents the CPU from
// spinning too busily and provides a balance between CPU spinning and
// the smallest possible interval timer.
static constexpr base::TimeDelta kMinimumInterval =
base::TimeDelta::FromMilliseconds(4);
Редактировать: Если вы читаете дальше в коде, этот минимум используется только в том случае, если уровень вложенности больше 5, однако он все равно устанавливает минимум на 1 мс во всех случаях:
base::TimeDelta interval_milliseconds =
std::max(base::TimeDelta::FromMilliseconds(1), interval);
if (interval_milliseconds < kMinimumInterval &&
nesting_level_ >= kMaxTimerNestingLevel)
interval_milliseconds = kMinimumInterval;
Видимо, Спецификации WHATWG и W3 C расходятся во мнениях относительно того, должно ли минимальное значение 4 мсек всегда применяться или применяться только выше определенного уровня вложенности, но значение WHATWG spe c имеет значение для HTML и похоже, что Chrome реализовал это.
Я не уверен, почему мои измерения показывают, что это все еще занимает 4 мс.
есть более быстрый способ сделать это?
Основываясь на прекрасной идее Kaiido использовать другой канал сообщений, вы можете сделать что-то вроде этого:
let currentTask = {
cancelled: false,
}
onmessage = event => {
currentTask.cancelled = true;
currentTask = {
cancelled: false,
};
performComputation(currentTask, event.data);
}
async function performComputation(task, data) {
let total = 0;
let promiseResolver;
const channel = new MessageChannel();
channel.port2.onmessage = event => {
promiseResolver();
};
while (data !== 0) {
// Do a little bit of computation.
total += data;
--data;
// Yield to the event loop.
const promise = new Promise(resolve => {
promiseResolver = resolve;
});
channel.port1.postMessage(null);
await promise;
// Check if this task has been superceded by another one.
if (task.cancelled) {
return;
}
}
// Return the result.
postMessage(total);
}
Я не совсем доволен этим кодом, но это кажется, работает и работает waaay быстрее. Каждый l oop занимает около 0,04 мс на моей машине.