减少浏览器长耗时怎么做

摘自

使用代码延迟任务执行

为了拆分长任务,开发者经常使用定时器 setTimeout。通过把方法传递给 setTimeout,也就等同于重新创建了一个新的任务,延迟了回调的执行,而且使用该方法,即便是将 delay 时间设定成 0,也是有效的。

缺点: 在需要循环中大量处理数据,(假设有百万数据)这个任务耗时就会非常长

 function saveSettings () {
   // Do critical work that is user-visible:
   validateForm();
   showSpinner();
   updateUI();

   // Defer work that isn't user-visible to a separate task:
   setTimeout(() => {
     saveToDatabase();
     sendAnalytics();
   }, 0);
 }

除了 setTimeout 的方式,确有一些 api 能够允许延迟代码到随后的任务中执行。其中一个方式便是使用 postMessage 替代定时器;也可以使用 requestIdleCallback,但是需要注意这个 api 编排的任务的优先级别最低,而且只会在浏览器空闲时才会执行。当主线程繁忙时,通过 requestIdleCallback 这个 api 编排的任务可能永远不会执行。

使用async await创建让步点

当让步于主线程后,浏览器就有机会处理那些更重要的任务,而不是放在队列中排队。理想状态下,一旦出现用户界面级别的任务,就应该让步给主线程,让任务更快的执行完。让步于主线程让更重要的工作能更快的完成

 function yieldToMain () {
   return new Promise(resolve => {
     setTimeout(resolve, 0);
   });
 }
 async function saveSettings () {
   // Create an array of functions to run:
   const tasks = [    validateForm,    showSpinner,    saveToDatabase,    updateUI,    sendAnalytics  ]

   // Loop over the tasks:
   while (tasks.length > 0) {
     // Shift the first task off the tasks array:
     const task = tasks.shift();

     // Run the task:
     task();

     // Yield to the main thread:
     await yieldToMain();
   }
 }

在这里插入图片描述

必要时让步

比如说,任务队列中有很多任务,但是不想阻挡用户输入,使用 isInputPending 和自定义方法 yieldToMain 方法,就能够保证用户交互时的 input 不会延迟。

浏览器支持该策略

 async function saveSettings () {
   // 函数队列
   const tasks = [    validateForm,    showSpinner,    saveToDatabase,    updateUI,    sendAnalytics  ];

   while (tasks.length > 0) {
     // 让步于用户输入
     if (navigator.scheduling.isInputPending()) {
       // 如果有用户输入在等待,则让步
       await yieldToMain();
     } else {
       // Shift the the task out of the queue:
       const task = tasks.shift();

       // Run the task:
       task();
     }
   }
 }

浏览器不支持,可以结合时间方式

async function saveSettings () {
   // A task queue of functions
   const tasks = [    validateForm,    showSpinner,    saveToDatabase,    updateUI,    sendAnalytics  ];

   let deadline = performance.now() + 50;

   while (tasks.length > 0) {
     // Optional chaining operator used here helps to avoid
     // errors in browsers that don't support `isInputPending`:
     if (navigator.scheduling?.isInputPending() || performance.now() >= deadline) {
       // There's a pending user input, or the
       // deadline has been reached. Yield here:
       await yieldToMain();

       // Extend the deadline:
       deadline += 50;

       // Stop the execution of the current loop and
       // move onto the next iteration:
       continue;
     }

     // Shift the the task out of the queue:
     const task = tasks.shift();

     // Run the task:
     task();
   }
 }

专门编排优先级的 api

该 api 提供 postTask 的功能,目前兼容性不太高
https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/postTask

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值