代码之家  ›  专栏  ›  技术社区  ›  Joji

尝试在生成器中使用setTimeout来控制生成随机数的过程,但失败了

  •  0
  • Joji  · 技术社区  · 6 年前

    我试图实现一个种子伪随机生成器。它会产生随机数,直到时间到了。代码如下

    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 . 我想循环并没有停止。那么出了什么问题?

    1 回复  |  直到 6 年前
        1
  •  4
  •   CertainPerformance    6 年前

    在回调有机会运行之前,脚本中的所有同步代码都将被执行。如果你有密码 阻碍 yield 在a中的ing 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毫秒内生成的元素数量可能有很大的范围,这取决于处理器/浏览器在这段时间内正在做什么。

    // 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);