Let us start with an example. Suppose, you are running a takeaway restaurant. Your menu includes 🍵(tea), ☕(coffee),🥪(sandwich) and 🍔(burger). Yes, you only serve four items for now 🤣. Currently, you operate via a single counter since you are the only employee. You have to take the order, do the billing, and prepare it, and all by yourself. Pretend you are a born multi-tasker 🦸♂️.
With that said, you can only serve a single customer at any point in time. The time to fulfil an order is as follows:
Since it is a single queue system even ☕ and 🍵 takers have to wait if they behind have any 🍔 or 🥪 buyers in the queue. People are people😬, and no one wants to spend their whole day just waiting in a long queue. Soon you found that you are losing the customers, all because of this long wait time😩.
Now the question is how can you retain your customers and earn more❓ The answer is super simple, reduce the wait time and server more people 🏆. Let us see two approaches (there are n other approaches as well).
We can add new 🤵(assistants) for processing the orders and 👨🍳(cooks) for preparation. Now an assistant/waiter will serve a burger or sandwich order. The ready to serve orders can be still managed by you🏋️♂️. Each time a 🍔 or 🥪 order comes up, you call upon a waiter to get it done. The waiter will take the order, inform the cook and wait until the cook prepares the order. Once it is ready, the order is well packed and handed over to the customer by the waiter. To ensure super fast delivery⚡️ for an order, a cook and a waiter work together from order taking to delivery. So the 🥪 and 🍔 customers are no more blocking the ☕ or 🍵 orders.
❎ The problem with this approach is, the waiter keeps on doing what they are meant to do, waiting... They are simply waiting 🏄🏾♀️ while the food is being cooked. Until an order is placed, the cook is waiting🏌🏾♂️ too. In short, now the waiter and cook waste a lot of time just, waiting.
Let us try introducing a 🏷(token) system only for the 🥪 and 🍔 orders. We take the order at a single counter and assign a 🏷 for each 🥪 and 🍔 orders. The customer clears the counter after collecting their token. Once the order is ready 🍛, the token number is called out 📣 and the 📦(parcel) is handed over through the main counter. Here too, we rely on extra 👨🍳(cooks) for preparation and a 🤵(single waiter). The called out customers join the queue to collect their order.
With this approach, the overall 🕰(time) has 📈increased (but still lower than the existing model), but the wait time is somewhat judiciously distributed.
Now let us get into the meat👽. The currently existing model of operation, the one before the optimization is kind of synchronous flow. Succeeding customers are awaiting for the previous order to be fulfilled. As the customers are blocked by the guys in front of them, we call it a blocking model.
The new two approaches can be considered as asynchronous or non-blocking (still there is a small wait time). As a separate 🤵-👨🍳 pair is working on a single order, the first approach is more like a multi-threaded one. The second approach is still kind of single-threaded but still unblocking.
If you were paying attention, by now you would have the answer...
JS has a single thread (in JS engine) which processes all your tasks. The time taking jobs(n/w calls, timing functions) are pushed out and processed by separate engines. Once they re done, they maintain a secondary queue(callback/microtask queue). Once the high priority/synchronous tasks are completed, the items in the secondary queue are pushed to the main queue(call stack), where they are served one by one, by the main thread. In short, we make the fewer priority tasks WAIT ⏰