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

Web工作者:Mobile Safari中的性能不一致?

  •  0
  • ultraGentle  · 技术社区  · 3 年前

    我在 web worker 将事件安排为相隔10毫秒。

    这似乎适用于除任何iOS浏览器之外的所有浏览器。(桌面旅行很好。)

    工人 <script> 标签:

    <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>
    

    主要的 <脚本> 标签(简化):

    let blob = new Blob([document.querySelector("#FastTimer").textContent]);
    let blobURL = window.URL.createObjectURL(blob);
    let worker = new Worker(blobURL);
    
    worker.addEventListener("message", receivedWorkerMessage);
    
    // simplified example of interacting with the timer
    function receivedWorkerMessage(event) {
        worker.postMessage(userInteractionData);
        doNextStepOfWork(); 
        counter++;  
    }
    

    欢迎提出任何建议/解释!

    注意事项:

    • 我试着用 setTimeout 基于定时器,但它太不精确了,对iOS根本没有帮助。
    • 我尝试了一种基于 requestAnimationFrame ,但在iOS中也不一致。
    • 我考虑过使用 AudioContext ,但我不想预先安排所有的活动,因为用户在活动进行时会与它们进行交互;但也许它可以作为计时器?
    0 回复  |  直到 3 年前
        1
  •  2
  •   VonC    3 年前

    由于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 ,用于提供执行的自定义音频处理脚本 在单独的线程中 以提供非常低延迟的音频处理。

    作为 documentation suggests ,您需要:

    1. 扩展 AudioWorkletProcessor 类(请参阅“ Deriving classes “部分)并提供您自己的 process() 方法;
    2. 使用注册处理器 AudioWorkletGlobalScope.registerProcessor() 方法
    3. 使用加载文件 addModule() 方法 audioWorklet 所有物
    4. 基于处理器创建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);
      };
    })();
    

    并致电您的员工:

    <脚本>
    const-worker=新worker('worker.js');
    
    worker.onmessage=函数(事件){
    //处理来自工作人员的消息
    console.log('从worker接收到的消息:',event.data);
    };
    </脚本>
    
        2
  •  1
  •   Thomas Frank    3 年前

    此构造

    while (Date.now() < startTime + delay) { }
    

    对计算机/设备不是很好。这相当于同时踩下油门和刹车踏板。您正在强制一个cpu 100%工作,直到您“暂停”了几毫秒。为什么?

    相反,只需使用setTimeout或setInterval,或者创建自己的异步睡眠函数:

    const sleep = ms => new Promise(res => setTimeout(res, ms));
    

    你可以这样称呼任何人 异步 功能:

    await sleep(milliseconds)
    

    或者,我问自己,我是不是错过了什么:这种浪费CPU功率的行为是一种更精确的计时器?所以我做了一些测试,比较调用while循环和 等待睡眠 以10ms作为延迟,然后用 性能.now 。两者似乎都很准确/不准确——在我的电脑上显示时间在9.5-10.5毫秒之间。那么,为什么要使用阻塞while循环(我知道它在工作线程中,所以它不会阻塞主线程)呢?这是对CPU周期/电池电量的浪费。。。

    推荐文章