After generating the first 10_000 primes, the UI bogs and becomes unresponsive!

// Prime Generator Tool
// Input: Data.value = 3
// Output Result.value = [2 3 5]
let __info__ = function(u){ Result.value = u } ;
let i = 3
let ret = [2]
let I = Data.value
while (ret.length < I)
{
let IncludeIDX = true
let MidwayPoint = i / 2
for (let u of ret)
{
if (u > MidwayPoint)
break
if (i % u == 0)
{
IncludeIDX = false
break
}
}
if (IncludeIDX)
ret.push(i)
i++
}
__info__(ret)

Further algorithmic optimizations, such as repeated square root, only lock up my browser for a shorter length of time!

I really need improved UI responsiveness.

How would I maybe convert this for-loop to an Async-Await, or Promise-based implementation?

FYI: I'm constructing a terrain generation tool which generates 1m x 1m grids of terrain,
contingent on rules for elevation, annual rainfall, and annual temperature (ie Earth Biomes).
Then joining them into contiguous blocks of 20 sq mi of terrain.

I've decided to model the internal configuration of each block, with sets of prime numbers -- which give me inherently nice properties,
such as magnitude-, displacement-, and scale-invariance, as well as fast rule-checking!

OK. I had a few issues; here's what I have working

Version 1 (My choice)

// Responsive UI and keyboard input, but laggy output; multiple invocations are hard to cancel
// Prime Generator Tool
// Input: Data.value = 3
// Output Result.value = [2 3 5]
let __info__ = function(u){ Result.value = u } ;
let i = 3
let ret = [2]
let I = Data.value
let winID = null
function NextStep()
{
if (ret.length < I)
{
let IncludeIDX = true
let MidwayPoint = i / 2
for (let u of ret)
{
if (u > MidwayPoint)
break
if (i % u == 0)
{
IncludeIDX = false
break
}
}
if (IncludeIDX)
ret.push(i)
i++
winID = requestIdleCallback(NextStep)
}
else
{
winID && cancelIdleCallback(winID)
__info__(ret)
}
}
winID = requestIdleCallback(NextStep)

Version 2

// Tolerable UI and keyboard input, but laggy output; multiple invocations are difficult to cancel
// Prime Generator Tool
// Input: Data.value = 3
// Output Result.value = [2 3 5]
let __info__ = function(u){ Result.value = u } ;
let i = 3
let ret = [2]
let I = Data.value
let winID = null
function NextStep()
{
if (ret.length < I)
{
let IncludeIDX = true
let MidwayPoint = i / 2
for (let u of ret)
{
if (u > MidwayPoint)
break
if (i % u == 0)
{
IncludeIDX = false
break
}
}
if (IncludeIDX)
ret.push(i)
i++
winID = requestAnimationFrame(NextStep)
}
else
{
winID && cancelAnimationFrame(winID)
__info__(ret)
}
}
winID = requestAnimationFrame(NextStep)

(Sigh), there is an adverse performance impact, as a trade-off for improved responsiveness. Multiple invocations, which update with keyboard input to Data.value, are near uncancel-able.

You should also consider putting this in a web worker.

Yes, this was a last resort. Code becomes less convenient for me, when dumping it to secondary files...

Added a DOM Element progress bar, for preemption, which works beautiful!

let __info__ = function(u){ Result.value = u } ;
let i = 3
let ret = [2]
let I = Data.value
let winID = null
function NextStep()
{
if (ret.length < I)
{
let IncludeIDX = true
let MidwayPoint = i / 2
// FIFO
if(ProgressBar.value > ret.length / I)
{
winID && cancelIdleCallback(winID)
ProgressBar.value = 0
return
}
// Progress Bar
ProgressBar.value = ret.length / I
// Prime Library
for (let u of ret)
{
if (u > MidwayPoint)
break
if (i % u == 0)
{
IncludeIDX = false
break
}
}
if (IncludeIDX)
ret.push(i)
i++
requestIdleCallback(NextStep)
}
else
{
winID && cancelIdleCallback(winID)
__info__(ret)
}
}
winID = requestIdleCallback(NextStep)

// Prime Generator Tool
// Input: __input__() // 3
// Output: __output__() // [2 3 5]
let __DEBUG__ = true
let i = 3
let ret = [2]
let I = __input__()
while (ret.length < I)
{
if (i % 2){
let IncludeIDX = true
let MidwayPoint = i / 2
for (let u of ret)
{
if (u > MidwayPoint)
break
if (i % u == 0)
{
IncludeIDX = false
break
}
}
if (IncludeIDX)
{
ret.push(i)
const v = ret.length / I
__progress__(v)
}
}
i++
}
__output__(ret)