Skip to content

The setTimeout function does not preserve FIFO ordering for equal delays #447

@a-serhiichyk-creatio

Description

@a-serhiichyk-creatio

When scheduling multiple timer callbacks with the same delay using worker-timers’ setTimeout, callbacks may fire out of order. This violates the HTML Standard’s requirement that timer callbacks enqueued on the same task source must execute in FIFO order when their delays expire simultaneously.

Steps to Reproduce

Schedule multiple callbacks synchronously with the same delay (e.g. 10 ms):

import { setTimeout as workerSetTimeout } from 'worker-timers';

(async () => {
	const results = [];
	await new Promise((resolve) => {
		for (let i = 1; i <= 10; i++) {
			workerSetTimeout(() => {
				results.push(i);
				if (results.length === 10) {
					resolve();
				}
			}, 10);
		}
	});
	alert(`Results: ${results.join(', ')}`);
})();

Expected result

Alert with (1, 2, 3, ...)

Actual result

Alert with numbers in quite a random order.

ℹ️ The issue can also be reproduced in Karma test like:

import { setTimeout as workerSetTimeout } from 'worker-timers';

describe('setTimeout order', () => {
	it('should resolve consequent setTimeout calls with the same delay in order 1', async () => {
		const results: number[] = [];
		await new Promise<void>((resolve) => {
			for (let i = 1; i <= 10; i++) {
				workerSetTimeout(() => {
					results.push(i);
					if (results.length === 10) {
						resolve();
					}
				}, 10);
			}
		});
		expect(results).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
	});
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions