function doUntil(loop, stopCondition, yieldCondition) { // Wrap function in promise so it can run asynchronously return new Promise((resolve, reject) => { // Build outerLoop function to pass to setTimeout let outerLoop = function () { while (true) { // Execute a single inner loop iteration loop(); if (stopCondition()) { // Resolve promise, exit outer loop, and do not re-enter resolve(); break; } else if (yieldCondition()) { // Exit outer loop and queue up next outer loop iteration // for next event cycle setTimeout(outerLoop, 0); break; } // Continue to next inner loop iteration without yielding } }; // Start the first iteration of outer loop, unless the stop condition is met if (!stopCondition()) { setTimeout(outerLoop, 0); } }); } // Check whether n is prime, given a list of all primes < n function isPrime(n, primes) { for (const p of primes) { if (n % p == 0) { return false; } } return true; } function findPrimesBlocking() { let primes = []; for (let n = 2; n < 1000000; n++) { if (isPrime(n, primes)) { primes.push(n); } if (n % 10000 == 0) { let status = `Found ${primes.length} primes between 2 and ${n}`; document.getElementById("display").textContent = status; console.log(status); } } document.getElementById("display").textContent = `Found ${primes.length} primes between 2 and 1000000`; } function findPrimesNonBlocking() { // Initialize loop variable and list of primes let n = 2; let primes = []; // Yield every 1000 iterations and stop after 1000000 const stopCondition = () => n == 1000000; const yieldCondition = () => n % 10000 == 0; // Build the loop body to be passed to doUntil() const loop = () => { // Determine if n is prime if (isPrime(n, primes)) { primes.push(n); } // Increment n n += 1; // Update DOM if we're about to yield if (yieldCondition()) { let status = `Found ${primes.length} primes between 2 and ${n}`; document.getElementById("display").textContent = status; console.log(status); } }; // Execute doUntil(loop, stopCondition, yieldCondition); }