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.

:rocket: Exploring Hybrid FIFO and LIFO Execution Patterns in JavaScript Environments

Hi @tc39 and JS enthusiasts,

While studying how JavaScript environments (such as browsers and Node.js) handle tasks through the event loop and microtask queues, a question came to mind:

Could a hybrid execution strategy—combining FIFO for independent tasks and LIFO for dependent/nested executions—bring measurable performance or clarity benefits in specific scenarios?

To clarify:

  • JavaScript currently uses a LIFO model in the call stack (as is natural with nested function calls), while task and microtask queues operate in a FIFO manner.
  • However, many tasks today are highly parallel and independent (e.g., UI updates, network responses, event handlers).

This leads me to wonder:
:backhand_index_pointing_right: Is there room for experimentation or discussion about optimizing or prioritizing certain "independent" microtasks or event tasks in a FIFO-like fashion, without interfering with the deterministic behavior JavaScript relies on?

I'm not suggesting a change to the language itself, but rather opening a conversation around possible scheduling strategies in engines or environments, especially with modern concurrency demands in mind.

Would love to hear your thoughts!

:rocket: Reconsidering Execution Strategies: Hybrid FIFO and LIFO Models in JavaScript Engines

Hello @tc39 and fellow JavaScript developers,

While exploring how JavaScript environments like browsers and Node.js handle task scheduling via the event loop and microtask queues, I began wondering:

Could a hybrid execution strategy—using FIFO for independent tasks and LIFO for nested/dependent ones—offer performance or clarity improvements in specific contexts?

Here’s the background:

  • JavaScript naturally uses a LIFO model for the call stack, due to the nature of nested function calls.
  • Meanwhile, both the task queue and microtask queue operate in a FIFO order.
  • However, many modern tasks—such as user interface updates, network responses, or asynchronous event handling—tend to be independent and parallelizable .

So the question is:
:backhand_index_pointing_right: Might there be potential in experimenting with hybrid scheduling approaches—where some "independent" tasks are optimized or prioritized differently—while still maintaining JavaScript's deterministic guarantees?

To be clear, I'm not proposing any changes to the language itself. Rather, I’m interested in exploring possible enhancements in the way engines or environments manage scheduling, especially in light of evolving concurrency needs.

Looking forward to hearing your insights and perspectives!

I don't think anyone here is interested in having a discussion about the JS language with an LLM, please revisit how you're using this tool to interact with the community.

1 Like

I'll be more explicit: it is incredibly rude to use an LLM to talk to a technical community like this. We see it as a complete waste of our time, and will treat it like the useless spam that it is (and treat you like any other spammer).

We have not yet baked this into our Code of Conduct, but we should probably look into doing so.