Javascript 使用setTimeout中断长时间运行的函数以允许事件处理

Javascript 使用setTimeout中断长时间运行的函数以允许事件处理,javascript,event-loop,Javascript,Event Loop,我必须找到一种方法来实现一个函数,该函数接受一个输入数字,并返回/显示最接近的较小素数或输入本身(如果它是素数) 然而,输入可能是一个非常大的数字,在这种情况下,内部函数会阻塞事件循环,我必须确保浏览器能够在计算期间处理事件 我的实现如下所示: function getClosestPrime(num) { return isPrime(num) ? num : getClosestPrime(num-1); } function isPrime(num) { for (let i

我必须找到一种方法来实现一个函数,该函数接受一个输入数字,并返回/显示最接近的较小素数或输入本身(如果它是素数)

然而,输入可能是一个非常大的数字,在这种情况下,内部函数会阻塞事件循环,我必须确保浏览器能够在计算期间处理事件

我的实现如下所示:

function getClosestPrime(num) {
    return isPrime(num) ? num : getClosestPrime(num-1);
}

function isPrime(num) {
  for (let i = 2; i < num; i++) {
    if(num % i === 0) return false;
    }
  return num !== 1;
}
函数getClosestPrime(num){ 返回isPrime(num)?num:getClosesPrime(num-1); } 函数isPrime(num){ for(设i=2;i 请有人帮我实施,并给我一个解释/提示,以供将来参考


提前感谢。

在承诺内使用setTimeout如何

function getClosestPrime(num) {
  return new Promise(resolve => {
    if (isPrime(num)) {
      resolve(num);
    } else {
      setTimeout(() => resolve(getClosestPrime(num-1)), 0);
    }
  })
}

function isPrime(num) {
  for (let i = 2; i < num; i++) {
    if(num % i === 0) return false;
  }
  return num !== 1;
}

setTimeout(() => alert("foo"), 0);     // 1st alerted
getClosestPrime(10000000).then(alert); // 3rd
setTimeout(() => alert("bar"), 0);     // 2nd
函数getClosestPrime(num){ 返回新承诺(解决=>{ if(isPrime(num)){ 解析(num); }否则{ setTimeout(()=>resolve(getClosestPrime(num-1)),0; } }) } 函数isPrime(num){ for(设i=2;i警报(“foo”),0);//第一警报 getClosestPrime(10000000)。然后(警报);//第三 setTimeout(()=>警报(“条”),0);//第二
因为JavaScript是单线程的,所以最好的解决方案是使用第二个线程来解决问题。这可以通过使用来实现

有了web worker,您的客户端算法就是:

  • 创建一个worker
  • 当我们希望它计算素数时,给它发送一条消息
  • 侦听一条名为“完成”的消息,这表示工作进程已完成
客户端代码:

// create the worker
var primeWorker = new Worker('calculate-prime.js');

function doPrimeComputationInWorker(number) {

  function handleWorkerCompletion(message) {
    if (message.data.command == 'done') {
      // update UI using the 'primeNumber' value received in the message 
      console.log(message.data.primeNumber);
      // remove the event listener
      primeWorker.removeEventListener('message', handleWorkerCompletion);
    }
  }

  // add the event listener
  primeWorker.addEventListener('message', handleWorkerCompletion, false);

  // post the number to the worker
  primeWorker.postMessage({
    'number': number
  });
}
代码应该足够简单,以便您遵循,您所要做的就是更改代码,以便在工作人员完成时更新UI

现在您需要web工作者代码。下面是
calculate prime.js
的框架:

// add the event listener
self.addEventListener('message', start);

function start(message) {
  // get the number value from the message
  var number = message.data.number;

  // perform the calculation
  var nearestPrime = calculateNearestPrime(number);

  // return the result
  self.postMessage({
    'command': 'done',
    'primeNumber': nearestPrime
  });
}

function calculateNearestPrime(number) {
  // your implementation goes here
  // return the result
  return result;
}
我将把质数的计算留给您,但是这个方法很容易实现,如果您不想自己编写代码,您可以在网上找到JavaScript实现。您可以使用来保存生成的素数列表,并加快未来的计算速度


作为将来的参考,您应该了解和,以便可以使用它们来解决异步问题

对于素数,使用这个。为可能的最大数量生成一次,然后在不计算的情况下使用它。对所有数字进行一次又一次的分析同样,为了实现一个非常简单的优化,在检查除数时,您只需将数字检查到
Math.floor(Math.sqrt(num))
。这将减少一半以上的迭代。您可能需要一个web工作人员在另一个线程中运行它。非常感谢您的回答和详细解释。我还不熟悉workers,所以这是一个练习和了解workers的好机会。Web workers非常适合从UI线程卸载工作。只是不要创建太多(100+),因为每一个都是处理器的新线程。我在
handleWorkerCompletion
函数中修复了代码示例
worker
应该是
primeWorker
。非常感谢,它工作得很好,并且在setTimout的回调没有立即启动时不会阻止事件处理,但有一点延迟(~1000ms)。