{
  "id": 16558827,
  "title": "Your loop yields every 500 items. It still freezes. Here's why (and a fix)",
  "url": "https://urgent.news/2026/10/26/your-loop-yields-every-500-items-it-still-freezes-heres-why-and-a-fix",
  "topic": "finance",
  "section": "Finance & Markets",
  "published": "2026-10-26T04:22:51.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/ragedpanda/your-loop-yields-every-500-items-it-still-freezes-heres-why-and-a-fix-3dki"
  },
  "original_language": "en",
  "account": "Every JavaScript developer eventually writes a loop that processes a large dataset by yielding control to the event loop every 500 items. This technique aims to prevent the UI from freezing or stalling the server while the loop executes. The basic idea is to perform some work, give the event loop a chance to run, and repeat the process. This method works in testing and staging environments. However, when the real-world data is introduced, the app may still freeze due to a cluster of heavy items appearing together in the loop.\n\nThe problem with the traditional approach lies in the assumption that each item costs the same amount of time to process. In reality, most items are small and take only microseconds to process, while a few items are heavy and take longer to handle. When a batch of heavy items shows up consecutively, the loop takes longer to complete, causing the app to freeze during that time.\n\nTo address this issue, the author developed the time-sliced library, which yields control based on time rather than the number of items. Instead of counting items, the library measures the time spent on processing each item. If the processing budget is spent (e.g., 8 ms by default), the library yields control to the event loop before continuing with the next item. This approach ensures that the app remains responsive even when encountering slow items in the dataset.\n\nThe API for the time-sliced library is simple. Developers can import the timeSlicedForEach function and apply it to their loop, specifying the rows to process and the function to execute for each row. The library provides a default budget of 8 ms per iteration, but developers can adjust this value based on their specific requirements.\n\nIn a real-world scenario, the author tested the time-sliced library with a dataset containing 20,000 rows, of which 1,000 were heavy and took 0.5 ms to process. The library was compared to several other common techniques, including a plain loop, async.eachSeries, setTimeout(0) every row, and setImmediate with 500-item intervals. The results showed that the time-sliced library completed the task in 921 ms with only an 11 ms event loop freeze, which was much faster than the other methods and prevented the app from freezing.\n\nThe library can be used with various types of loops, including nested, while, and recursive loops. For example, it can be used to update a search index or process CSV rows, ensuring that the app remains responsive during these operations. Additionally, the time-sliced library can be canceled using an AbortController, making it ideal for use cases such as search-as-you-type functionality.",
  "summary": "Every JavaScript developer eventually writes this loop: for ( const [ index , row ] of rows . entries ()) { processRow ( row ); if ( index % 500 === 0 ) await new Promise ( resolve => setImmediate ( resolve )); } It's the textbook fix for a long loop that freezes the UI or stalls a server: do some work, give the event loop a turn, repeat. It works in testing. It works in staging. Then production…",
  "key_points": [
    "Traditional loop yields control every 500 items to prevent UI freeze",
    "Heavy items in dataset cause loop to freeze despite technique",
    "Time-sliced library yields control based on processing time, not item count"
  ],
  "editors_take": "Shifting from item-based intervals to time-based slicing protects application responsiveness by preventing consecutive heavy data entries from overwhelming the event loop and causing interface freezes.",
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}