javascript - 尝试在生成器中使用 setTimeout 来控制生成随机数的过程,但失败了
问题描述
我试图实现一个种子伪随机生成器。它将产生随机数,直到时间结束。代码如下
function* pseudoRandom(seed) {
let random = seed;
let flag = true;
setTimeout(() => {flag = !flag}, 100); // stop generating after 100ms
while (flag) {
random = random * 16807 % 2147483647;
yield random;
}
}
let generator = pseudoRandom(1);
console.log([...generator]);
但我仍然收到错误消息FATAL ERROR: invalid array length Allocation failed - JavaScript heap out of memory
。我猜循环没有停止。那么出了什么问题呢?
解决方案
脚本中的所有同步代码都将在回调有机会运行之前执行。如果你有阻塞yield
的代码(比如无限while
循环而不停止),回调将永远没有机会运行。
出于类似的原因,以下代码将永远不会退出while
循环:
let flag = false;
setTimeout(() => flag = true);
while (!flag) {
// do something
}
检查循环内是否已经过去了 100 毫秒:
function* pseudoRandom(seed) {
let random = seed;
const start = Date.now();
while (Date.now() - start < 100) { // stop generating after 100ms
random = random * 16807 % 2147483647;
yield random;
}
}
let generator = pseudoRandom(1);
console.log([...generator].length);
请注意,在 100 毫秒内生成的元素数量可能有很大的范围,这取决于处理器/浏览器在此期间所做的其他事情。
感谢 Kaiido,为了避免阻塞可见的 UI,您可以考虑将脚本的阻塞部分移动到工作人员:
// https://stackoverflow.com/questions/10343913/how-to-create-a-web-worker-from-a-string
// I put in a Stack Snippet for live demonstration
// in a real project, put this in a separate file
const workerFn = () => {
function* pseudoRandom(seed) {
let random = seed;
const start = Date.now();
while (Date.now() - start < 100) { // stop generating after 100ms
random = random * 16807 % 2147483647;
yield random;
}
}
self.onmessage = ({ data }) => {
let generator = pseudoRandom(1);
const arr = [...generator];
self.postMessage(arr.length);
};
};
const workerFnStr = `(${workerFn})();`;
const blob = new Blob([workerFnStr], { type: 'text/javascript' });
const worker = new Worker(window.URL.createObjectURL(blob));
worker.onmessage = ({ data: length }) => console.log(length);
worker.postMessage(1234);
推荐阅读
- angular - 如何在 Angular View 组件中添加动态布局?
- go - 最小正 float64 值
- powerpoint - PPTX文件中不同文件的说明
- c# - C# GetActiveTcpConnections() 仅关于一个应用程序
- java - 在单独的 maven 项目中引用另一个 drl 文件中的函数
- phpmailer - 您可以仅在 phpmailer 中指定 TLS v1.3 吗?
- python - 用于从 R 到 python 的循环转换以迭代 pandas 数据帧
- android - 运行后台线程时跳过协程
- vb.net - vb.net 不会使用 htmlagilitypack 检索数据
- python - 在 Pycharm 中找不到 WSL 解释器添加 python 解释器屏幕