我必须找到一种方法来实现一个函数,该函数接受一个输入数字并返回/显示最接近的较小素数或输入本身(如果它是素数)。
但是,输入可能是一个非常大的数字,在这种情况下,内部函数会阻止事件循环,我必须确保浏览器能够在计算过程中处理事件。
我的实现如下:
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;
}
有人可以帮助我实施并给我一个解释/提示以备将来参考吗?
提前致谢。
答案 0 :(得分:2)
因为JavaScript是单线程的,所以最好的解决方案是获得第二个线程来为您解决问题。这可以通过使用Web Workers API来实现。
有了Web工作人员,您的客户端算法就是:
客户端代码:
// 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 worker代码。这是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;
}
我会将素数的计算留给您,但Sieve of Eratosthenes很容易实现,如果您不想自己编写代码,您会在线找到JavaScript实现。您可以使用Web Storage API保存生成的素数列表并加快将来的计算。
为了将来参考,您应该了解Promises和Generators,以便您可以使用它们来解决异步问题。
答案 1 :(得分:1)
如何在Promise中使用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