Calculating Primes with Async-Await and Promises

Calculating Primes

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!

You can simply put a

if (!deadline.timeRemaining()) {
  deadline = await new Promise(resolve => { requestIdleCallback(resolve); });
}

in your outer loop.

You should also consider putting this in a web worker.

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...

I'll try your code, above, as written.

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)

An even faster sieve for the remaining odd primes

// 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)