我正在编写一个用JavaScript生成素数的程序。问题是程序的行为很奇怪,似乎函数没有按顺序执行,导致它无法正常执行。这是我的代码:
<!DOCTYPE html>
<html>
<head>
<title>Generate Some Primes!</title>
</head>
<body>
<h1>Let's Generate Some Primes!!!</h1>
<form id="userInput">
<ul>
<li>
<label>Lower Bound (inclusive):</label>
<input type="number" id="lower">
</li>
<li>
<label>Upper Bound (exclusive):</label>
<input type="number" id="upper">
</li>
<li>
<input type="submit" value="Generate!">
</li>
</ul>
</form>
<p id="messageBox"></p>
<ul id="primes"></ul>
<script>
var primesList = document.getElementById("primes");
var lower;
var upper;
var NOT_STARTED = "Generating ...";
var DONE = "Done!";
window.onload = function() {
userInput.onsubmit = function(e) {
e.preventDefault();
writeMessage(NOT_STARTED);
if (checkInput()) {
checkNumbers();
writeMessage(DONE);
}
}
}
function checkInput() {
initializeBounds();
if (lower >= upper) {
writeMessage("Lower bound must be less than upper bound.");
return false;
}
return true;
}
function initializeBounds() {
lower = Math.round(document.getElementById("lower").value);
upper = Math.round(document.getElementById("upper").value);
primesList.innerHTML = "";
}
function checkNumbers() {
for (var i = lower; i < upper; i++) {
if (isPrime(i))
writePrime(i);
}
}
function writePrime(p) {
primesList.innerHTML += "<li>" + p + "</li>";
}
function writeMessage(message) {
var messageBox = document.getElementById("messageBox");
messageBox.innerHTML = message;
}
function isPrime(p) {
if (p < 2)
return false;
for (var b = p - 1; b > 1; b--)
if (GCD(p, b) > 1)
return false;
return true;
}
function GCD(a, b) {
if (b == 0)
return a;
else
return GCD(b, a % b);
}
</script>
</body>
</html>
这些是我的问题:
当下限接近上限时,它们都是相对较大的数字,没有产生输出(例如尝试输入900作为下限和1000作为上限),即使我知道肯定存在素数,并且我生成它们的方法也有效。
素数应该在生成时显示在屏幕上,而不是在它们全部创建时显示在最后。如果您输入0作为下限,10000作为上限,您将清楚地看到此问题(我建议运行整个片段并观察滚动条大小)。
这与数字2相关。Generating ...
消息永远不会显示,只会显示Done
。
编辑:我对解决第一个问题的代码做了一些更改。
答案 0 :(得分:1)
我建议使用Promises来打破for循环的阻塞行为,并为浏览器/ UI提供足够的时间来呈现结果。
<body>
<h1>Let's Generate Some Primes!!!</h1>
<form id="userInput">
<ul>
<li>
<label>Lower Bound (inclusive):</label>
<input type="number" id="lower">
</li>
<li>
<label>Upper Bound (exclusive):</label>
<input type="number" id="upper">
</li>
<li>
<input type="submit" value="Generate!">
</li>
</ul>
</form>
<p id="messageBox"></p>
<ul id="primes"></ul>
<script>
var primesList = document.getElementById("primes");
var lower;
var upper;
var NOT_STARTED = "Generating ...";
var DONE = "Done!";
window.onload = function() {
userInput.onsubmit = function(e) {
e.preventDefault();
writeMessage(NOT_STARTED);
if (checkInput()) {
checkNumbers()
.then(function() {
writeMessage(DONE);
})
}
}
}
function checkInput() {
initializeBounds();
if (lower >= upper) {
writeMessage("Lower bound must be less than upper bound.");
return false;
}
return true;
}
function initializeBounds() {
lower = Math.round(document.getElementById("lower").value);
upper = Math.round(document.getElementById("upper").value);
primesList.innerHTML = "";
}
function checkNumbers() {
var promise = Promise.resolve();
for (var i = lower; i < upper; i++) {
(function(i) {
promise = promise.then(function() {
if (isPrime(i))
return writePrime(i);
});
})(i);
}
return promise;
}
function writePrime(p) {
return new Promise(function(resolve, reject) {
primesList.innerHTML += "<li>" + p + "</li>";
writeMessage("Generating ..." + Math.round(100 * p / (upper - lower)) + "%");
setTimeout(function() {
resolve();
}, 0);
});
}
function writeMessage(message) {
var messageBox = document.getElementById("messageBox");
messageBox.innerHTML = message;
}
function isPrime(p) {
if (p < 2)
return false;
for (var b = p - 1; b > 1; b--)
if (GCD(p, b) > 1)
return false;
return true;
}
function GCD(a, b) {
if (b == 0)
return a;
else
return GCD(b, a % b);
}
</script>
</body>
&#13;
jsFiddle的外部链接。
答案 1 :(得分:0)
1 :使用parseInt()
将输入(字符串)正确转换为数字。
2,3 :for
循环阻塞了窗口线程,因此这就是您没有看到逐步结果的原因;只有在代码完成时才会刷新DOM。实际上正在设置该消息,但由于该进程被阻止,您无法看到它。
我已使用setTimeout()
功能对您的代码段进行了编辑,该功能会在通话前等待一段时间。
<!DOCTYPE html>
<html>
<head>
<title>Generate Some Primes!</title>
</head>
<body>
<h1>Let's Generate Some Primes!!!</h1>
<form id="userInput">
<ul>
<li>
<label>Lower Bound (inclusive):</label>
<input type="number" id="lower">
</li>
<li>
<label>Upper Bound (exclusive):</label>
<input type="number" id="upper">
</li>
<li>
<input type="submit" value="Generate!">
</li>
</ul>
</form>
<p id="progress"></p>
<ul id="primes"></ul>
<script>
var primesList = document.getElementById("primes");
var lower;
var upper;
var NOT_STARTED = false;
var DONE = true;
window.onload = function() {
userInput.onsubmit = function(e) {
e.preventDefault();
/* 3: let's give some time for message */
writeProgressMessage(NOT_STARTED);
initializeBounds();
window.setTimeout(function () {
checkNumbers(lower, upper);
}, 1000); // waiting for 1s to start
}
}
function initializeBounds() {
/* correctly convert the input's for numbers, using parseInt */
lower = parseInt(document.getElementById("lower").value, 10);
upper = parseInt(document.getElementById("upper").value, 10);
primesList.innerHTML = "";
}
function checkNumbers(current, upper) {
if (isPrime(current))
writePrime(current);
/* not yet finished */
if (current != upper) {
setTimeout(function () {
checkNumbers(current+1, upper);
}, 100); // wait 100ms for the next check
}
}
function writePrime(p) {
primesList.innerHTML += "<li>" + p + "</li>";
}
function writeProgressMessage(done) {
var progress = document.getElementById("progress");
if (!done)
progress.innerHTML = "Generating ...";
else
progress.innerHTML = "Done!";
}
function isPrime(p) {
if (p < 2 || !Number.isInteger(p))
return false;
for (var b = p - 1; b > 1; b--)
if (GCD(p, b) > 1)
return false;
return true;
}
function GCD(a, b) {
if (b == 0)
return a;
else
return GCD(b, a % b);
}
</script>
</body>
</html>