文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

新颖的 setTimeout() 替代方案

2024-11-29 18:07

关注

长任务的问题

为了说明长任务的问题,以下是一个示例,任何字符都有其代码,但并非所有代码都有相关字符。所有非字符代码都显示为白色垂直矩形。您可以在下面显示与一系列代码相对应的字符的页面中看到许多代码:

图片

有很多垂直的矩形,想把它们过滤掉,通过遍历一系列Unicode字符代码,过滤掉未分配的代码点。

const MIN = 127734, MAX = 129686;

function insertChar(code, parent) {
    parent.insertAdjacentText('beforeend', String.fromCodePoint(code));
}

function add(i, parent) {
    if (!likeNull(i)) // 比较字符i和0的canvas
        insertChar(i, parent);
}

function one(div) {
    for (let i = MIN; i < MAX; i++)
        add(i, div);
}

function onClick(func) {
    btn.addEventListener('click', async () => {
        btn.remove();
        const start = Date.now();
        await func(div);
        div.insertAdjacentText("afterend", Date.now() - start);
    });
}

onClick(one);

图片

这段代码在执行过程中会使页面冻结约4279毫秒,而在此期间,页面一直处于冻结状态。即使点击后代码会首先移除按钮,但只要代码还在运行,浏览器就无法更新屏幕。代码运行结束后,浏览器也无法显示任何字符,按钮会被移除,字符也会一并显示, 导致用户体验不佳。

因此,在长时间工作时,一定要暂停,让浏览器更新屏幕。可以使用类似的语句暂时中止或中断长代码的执行.

使用setTimeout()分割任务

传统的解决方法是使用setTimeout()来分割任务:

function pause() {
    return new Promise(resolve => setTimeout(resolve));
}

async function two(div) {
    for (let i = MIN; i < MAX; i++) {
        await pause();
        add(i, div);
    }
}

onClick(two);

图片

这种方法虽然使页面保持响应,但执行时间显著增加到约17568毫秒。

setTimeout()的缺点

最小超时时间为4毫秒,即使指定为0

即使浏览器无事可做,主任务也会暂停至少 4 毫秒。即使指定为零,setTimeout()的最小超时时间 也是 >4 ms。事实上,让我们来计算一下。在第一页中,评估 1952 个代码点需要 4279 毫秒,即每个代码需要 ~2 毫秒。在第二个页面中,评估 1952 个代码点需要 17568 毫秒,即每个代码点 ~17568/1952=9毫秒。页面响应速度保持不变,但性能下降也令人印象深刻,这主要是由于超时的持续时间尽可能短。

任务继续执行时被放置在队列末尾,可能导致优先级问题。

当任务暂停时,setTimeout() 会将其作为一个新任务放置在队列的最末端。因此,浏览器不仅会更新屏幕,还会先执行队列中的所有任务,然后再继续执行暂停的任务。

图片

在上面的页面中,两个函数two()同时运行:

onClick(()=>Promise.race([two(div),two(div2)]));

当第一个two()提交给主线程时,第二个two()会在第一个two()继续执行之前被执行。执行时间会稍有增加,从 17 秒增加到 23 秒,但不会增加两倍,因为大部分运行时间都是由最小超时加起来的。

scheduler.yield():新的解决方案

scheduler.yield()提供了一种更高效的方法来让出主线程:

async function three(div) {
    for (let i = MIN; i < MAX; i++) {
        await scheduler.yield();
        add(i, div);
    }
}

onClick(three);

图片

使用scheduler.yield(),执行时间减少到约5646毫秒,显著优于setTimeout()方法。

scheduler.yield()的优势

  1. 更高的性能:执行时间更接近于未中断的任务。
  2. 优先级处理:被暂停的任务被放置在队列头部,而不是末尾。

示例比较:

// 同时执行两个three()函数
onClick(() => Promise.race([three(div), three(div2)]));

// three()与setTimeout()基于的two()比较
onClick(() => Promise.race([three(div), two(div2)]));

结果与上述基于setTimeout()的index4.html的不同之处仅在于执行时间。10183 毫秒相当于两次 5645 毫秒。两个任务似乎都没有优先级。

优先级似乎不起作用,因为两个函数three()都不在队列中等待。但看看这个:

图片

在与setTimeout()基于的方法比较时,scheduler.yield()显示出明显的优先级优势。

结语

scheduler.yield()为JavaScript中的任务调度提供了一个强大的新工具。它不仅性能更优,还能更好地处理任务优先级。对于需要处理长时间运行任务的前端开发者来说,这是一个值得关注和采用的新技术。

在实际应用中,开发者可以考虑在处理大量数据处理、复杂计算或频繁DOM操作等场景时使用scheduler.yield()。这将有助于保持页面的响应性,同时不会显著影响任务的执行效率。随着浏览器支持的增加,scheduler.yield()有望成为前端性能优化的重要工具。

来源:大迁世界内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯