# requestIdleCallback

window.requestIdleCallback()方法插入一个函数,这个函数将在浏览器空闲时期被调用。这使开发者能够在主事件循环上执行后台和低优先级工作,而不会影响延迟关键事件,如动画和输入响应。函数一般会按先进先调用的顺序执行,然而,如果回调函数指定了执行超时时间timeout,则有可能为了在超时前执行函数而打乱执行顺序。

你可以在空闲回调函数中调用requestIdleCallback(),以便在下一次通过事件循环之前调度另一个回调。

强烈建议使用timeout选项进行必要的工作,否则可能会在触发回调之前经过几秒钟。

var handle = window.requestIdleCallback(callback[, options])
  • callback
    • 一个在事件循环空闲时即将被调用的函数的引用。函数会接收到一个名为 IdleDeadline 的参数,这个参数可以获取当前空闲时间以及回调是否在超时时间前已经执行的状态。
  • options 可选,包括可选的配置参数。具有如下属性:
    • timeout: 如果指定了timeout,并且有一个正值,而回调在timeout毫秒过后还没有被调用,那么回调任务将放入事件循环中排队,即使这样做有可能对性能产生负面影响。

# window.cancelIdleCallback()

window.cancelIdleCallback() 方法用于取消之前调用window.requestIdleCallback() 的回调。

window.cancelIdleCallback(handle);
//调用 window.requestIdleCallback()  时返回的 ID.
    // 60fps
    // 1秒渲染60次 渲染1次 1帧,大概16.6ms
    // |帧(system task,render,script)空闲时间  |帧 painting idle   |帧   |帧   |
    // 借鉴fiber架构
    async calculateHashIdle(){
      const chunks = this.chunks
      return new Promise(resolve=>{
        const spark = new sparkMD5.ArrayBuffer()
        let count = 0 

        const appendToSpark = async file=>{
          return new Promise(resolve=>{
            const reader = new FileReader()
            reader.readAsArrayBuffer(file)
            reader.onload = e=>{
              spark.append(e.target.result)
              resolve()
            }
          })
        }
        const workLoop = async deadline=>{
          // timeRemaining获取当前帧的剩余时间
          while(count<chunks.length && deadline.timeRemaining()>1){
            // 空闲时间,且有任务
            await appendToSpark(chunks[count].file)
            count++
            if(count<chunks.length){
              this.hashProgress = Number(
                ((100*count)/chunks.length).toFixed(2)
              )
            }else{
              this.hashProgress = 100
              resolve(spark.end())
            }
          }
          window.requestIdleCallback(workLoop)
        }
        // 浏览器一旦空闲,就会调用workLoop
        window.requestIdleCallback(workLoop)

      })
    }
// 斐波那契数列函数  
function fibonacci(n) {  
  if (n <= 1) return n;  
  return fibonacci(n - 1) + fibonacci(n - 2);  
}  
  
// 使用requestIdleCallback的任务函数  
function workLoop(deadline) { 
  // console.log(deadline.timeRemaining())
  while (deadline.timeRemaining() > 0 && tasks.length > 0) {  
    const task = tasks.shift();  
    // 假设每个任务都是计算斐波那契数列的某个值  
    const result = fibonacci(task);  
    console.log(`Fibonacci(${task}) = ${result}`);  
  }  
  
  if (tasks.length > 0) {  
    // 如果还有任务剩余,请求下一个空闲回调  
    requestIdleCallback(workLoop);  
  }  
}  
  
// 存储待处理的任务(斐波那契数列的索引)  
const tasks = [30, 31, 32, 33, 34, 35,36,37,38];  
  
// 启动工作循环  
requestIdleCallback(workLoop);
最后更新: 4/25/2024, 9:09:06 AM