Mixing FIFO and LIFO in JavaScript's Event Loop

:rocket:** Improving JavaScript Performance with FIFO and LIFO Handling in the Event Loop**

Hey @tc39, I have a concept that could potentially optimize JavaScript’s event handling process. Currently, JavaScript uses LIFO (Last In, First Out) for managing tasks in the call stack, but I believe that mixing FIFO (First In, First Out) for non-interdependent tasks could increase performance in certain scenarios.

Here's the idea:

  1. For independent tasks (those without dependencies or nested functions), they could be handled with FIFO, ensuring that tasks are executed in the order they are added.
  2. For nested functions (those dependent on others), we continue using LIFO for handling them, just as JavaScript does now.

This hybrid approach would allow:

  • Faster handling of simple tasks by executing them in the order they arrive (FIFO).
  • No need for the Event Loop to check if the stack is empty before transferring tasks from the callback queue to the call stack.
  • Potential improvements in performance and concurrency management.

What do you think, @tc39? Could this be a useful change to consider for future ECMAScript versions?

The event loop isn't part of JS, it's part of the Web (and node).

Separately, what about Promises isn't FIFO?

1 Like

Not sure what you mean by "managing tasks" here. The call stack simply represents nested function calls.

That is already how it works. The event queue (as used e.g. in web browsers and node.js) and the microtask queue (for promise reactions) do exactly this.

I don't think you understand how the event loop works. There is no such "check whether the stack is empty".

2 Likes

you're telling about pipeline pattern that is not a part of promise but javascript allows it to define it using promise sugar.

they're like each other but different.

imagine tree. you can traverse tree deep-first like 1 -> 1.1 -> 1.1.1 -> 1.2 -> 1.2.1

also you can traverse tree breadth first 1 -> 1.1 -> 1.2 -> 1.1.1 -> 1.2.1

this is different cases.

actually promise works like breadth first but "not as tree" at all

promise creates object that never arrive to any tree and actually arrive to nothing except your code - once reference is removed - object will be removed too. Promise objects keeps the subscribers (the ones that called then/catch/finally) as the children, but once you call resolve/reject - the childrens become clear and now reference is free to be removed once you leave current function scope.

Theres not queue-of-promises. but calling then/catch/finally creates new callback in callback-queue depending on resolved/rejected state. And that queue will work like "do all microtasks until they're exists". Each mircotask encloses reference to the promise or resolver prevents it to be removed without any action.

that can be virtually drawn like breadth-first behavior

you're asking for PIPELINE pattern, that is store child-callbacks inside. And actually the PIPE is variety of callback (or even "plain function")

plain function works synchronyous and contain methods/calls/actions that is like "leafs of the chain" and it will be done syncronyous, as fast as possible

but in real practice you most of the times DEBUG your code and the process is not very simple to stay in plain methods paradigm.

short calls like map/reduce/tap is SLOWER than one function with several for loops, but more readable and allows to add additional steps in human-readable notation. you can add or remove steps using delete line and copy line in your IDE.

so this is not a problem of performance but problem of readability

writing pipe with, for example, map-reduces-filters for the CPU is the same (actually slower, because you spent time to run additional function, and possible create different scope for it) as you write plain method with for loops, but less debugable and can do more side effects to other code being changed.

thats why the pipe pattern looks great, because you can omit changing ready function just combine them human-readable way.

as i understand with my 15 years of PHP experience, that correct working flow in any company should be "you can FIX old code only if you're AUTHOR of the code, otherwise you spent time less productive that you can be". But business never listen developers and continues to hire people to change old basements with forces of new people - its like rebuilding house basement everyday.

Actually bugged code should be removed and written from scratch to always keep guru that knows how it works and how it can be fixed. So pipeline-vs-plain_functions its like that business situation. With pipeline you never touch functions just remove/replace ready black-boxes, so you risk less. But it works little bit slower. But edited 3 times faster. Or-or.

Am I making myself clear enough?

1 Like

Also, the call stack is naturally already back to how it was before calling anything. There's nothing to preserve, nothing to nest into. I'm not sure they even know how calling functions works.

1 Like

This reads pretty strongly as an LLM-generated post.

1 Like

Maybe not fully, but definitely for the most part.

Highly technical discussions are areas where current LLMs will fail you. They are terrible at generalizing the math correctly, and it shows.

I could totally see an LLM making a connection between function nesting and call stack nesting simply through the concept of "nesting", and just running with it like it's actually similar under the hood.