строка
promise.then(onFullfiled).catch(onRejected);
на самом деле работает как
promise.then(onFullfiled, err => {throw err;}).then(v => v, onRejected);
Если имеем дело с зарезолвленным/зареджекченным промисом, то здесь первый then ставит микротаск в очередь сразу, а второй - только по выполнении микротаска от первого.
соответственно, для примера
const promises = [
Promise.reject('rejected1'),
Promise.reject('rejected2'),
Promise.resolve('resolved'),
];
микротаски составили такую очередь:
1) err => {throw err;}
2) err => {throw err;}
3) onFullfiled
4) onRejected,
5) onRejected
6) v => v,
Где пункты 1-3 добавились на цикле, а 4-6 по мере выполнения первых трёх.
вот так и вышло, что onFullfiled вылез вперед.