Web worker作为精确计时器:在iOS中不一致?

olmpazwi  于 2023-05-02  发布在  iOS
关注(0)|答案(1)|浏览(223)

bounty还有6天到期。回答此问题可获得+50声望奖励。ultraGentle正在寻找典型答案

我在一个web worker中使用以下代码来调度事件,使其精确间隔10 ms。
这似乎适用于所有浏览器,除了任何iOS浏览器。(桌面Safari很好。)

<script id="masterClock" type="javascript/worker">
  let onmessage = function (event) {
    let delay = 10; // milliseconds
    let time = Date.now();
    while (Date.now() < time + delay) { }; // waits 10ms increments in all browsers except mobile Safari
    postMessage({data: []});
  };
</script>

任何建议/解释赞赏!
编辑:

  • 我尝试使用基于setTimeout的计时器,但它太不精确了,对iOS一点帮助都没有。
  • 我尝试了基于requestAnimationFrame的替代计时器,但它在iOS中也不一致。
  • 我考虑过使用AudioContext,但我不想预先安排所有事件,因为用户会在事件发生时与它们交互;但也许它可以作为计时器
wvt8vs2t

wvt8vs2t1#

由于iOS设备可能具有电源管理功能,可以在后台或屏幕关闭时限制或降低JavaScript执行的优先级(如this thread所示),因此您可能需要考虑另一种后台任务机制。
尝试一个Web API Worker,它会调用你的javascript循环:

<script>
  const worker = new Worker('worker.js');

  worker.onmessage = function (event) {
    // Handle the message from the worker
    console.log('Message received from worker:', event.data);
  };
</script>

你的剧本:

let delay = 10; // milliseconds

function timer() {
  let startTime = Date.now();
  while (Date.now() < startTime + delay) {}
  postMessage({data: []});
  setTimeout(timer, delay);
}

timer();

但如果问题仍然存在,那么是的,音频工作者更精确。由于您需要保持交互,因此考虑使用Audio Worklet API,它用于提供自定义音频处理脚本,这些脚本在单独的线程中执行,以提供非常低的延迟音频处理。
如文档所示,您需要:
1.扩展AudioWorkletProcessor类(参见“派生类”一节)并在其中提供您自己的process()方法;
1.使用AudioWorkletGlobalScope.registerProcessor()方法注册处理器;
1.在音频上下文的audioWorklet属性上使用addModule()方法加载文件;
1.基于处理器创建AudioWorkletNode。处理器将由AudioWorkletNode构造函数在内部示例化。
创建一个audio-worklet-processor.js

class TimerProcessor extends AudioWorkletProcessor {
  static get parameterDescriptors() {
    return [{ name: 'delay', defaultValue: 10 }];
  }

  constructor() {
    super();
    this.timer = 0;
  }

  process(inputs, outputs, parameters) {
    const delay = parameters.delay[0] || 10;
    this.timer += 128 / sampleRate * 1000; // 128 is the default buffer size

    if (this.timer >= delay) {
      this.timer -= delay;
      this.port.postMessage({ data: [] });
    }

    return true; // Keep the processor alive
  }
}

registerProcessor('timer-processor', TimerProcessor);

您可以从worker.js注册它:

(async () => {
  // Load the audio worklet processor
  const audioContext = new AudioContext();
  await audioContext.audioWorklet.addModule('audio-worklet-processor.js');

  // Create the audio worklet node and connect it to the destination
  const timerNode = new AudioWorkletNode(audioContext, 'timer-processor');
  timerNode.connect(audioContext.destination);

  // Set up a message listener
  timerNode.port.onmessage = (event) => {
    // Handle the message from the audio worklet processor
    console.log('Message received from audio worklet processor:', event.data);
  };
})();

打电话给你的员工:

<script>
  const worker = new Worker('worker.js');

  worker.onmessage = function (event) {
    // Handle the message from the worker
    console.log('Message received from worker:', event.data);
  };
</script>

相关问题