Remix是一个基于嵌套路由、服务端渲染与Web Fetch API的全栈JavaScript框架,由React Router团队于2020年创立、2021年10月发布,2022年被Shopify收购并持续开源,核心目标是优化数据加载与代码分割体验。

学 JS 长任务拆分的高级编程模式,关键不是堆砌 API,而是建立“主线程调度权意识”:清楚什么时候该交出控制权、交给谁(宏任务?idle?Worker?)、交多久、交完怎么接上。它是一套围绕浏览器渲染帧节奏展开的协作逻辑,不是单点技巧的拼凑。
从识别真瓶颈开始,别被表象骗
很多所谓“长任务”其实不来自 JS 执行本身,而是隐性开销:
- Performance 面板里标红的 [Long Task] 是硬指标,但更要盯 Scripting 区域是否连续占满——如果是,说明计算没让权;如果是 Layout/Paint 高频跳动,问题大概率在 DOM 操作方式,比如循环中反复读 offsetHeight 或 getBoundingClientRect()
- 单次插入 200 个节点不慢,但若每个都带内联样式 + 强制 layout 计算,就会触发多次重排。此时切片无用,得先改操作模式:缓存读取、批量写入、统一走 DocumentFragment
- 别信 Promise.then() 是异步救星——链式嵌套过深、错误未捕获,容易中断流程;requestIdleCallback 不设 timeout,可能永不执行
按任务性质选调度锚点,不是按 API 名字选
不同场景下,“让权”的时机和粒度完全不同:
- 海量 DOM 渲染(如万级列表、日历月视图):以“可视区优先 + 单元切片”为原则。例如日历按“天”为单位分块,每块处理前用 deadline.timeRemaining() > 1 判断是否继续,超时立刻移交控制权
- 启动初始化(SPA 加载):必须同步项(如根节点挂载)留主线程;非首屏预加载、埋点 SDK 初始化等归入低优队列,用 requestIdleCallback 或降级 setTimeout(, 0) 延后,且必须设 timeout: 2000
- 纯计算密集型(JSON 解析、大数据聚合):禁用 for/while 一口气跑完。改用 chunked 分片(如每批 300 条),每批结束用 setTimeout 主动让权——这是宏任务作为切片边界的典型用法
微任务和宏任务不是并列选项,是协作层级
它们天然承担不同角色,混用或错位会放大卡顿:
- 宏任务(setTimeout / setImmediate):唯一能真正释放渲染权的手段,适合做主切片边界。例如“处理完一批就 setTimeout 启动下一批”,确保浏览器有机会画帧、响应点击
- 微任务(queueMicrotask):适合批内快速串联,比如校验 → 格式化 → 缓存到局部数组,全程无延迟但不释放主线程。不能替代宏任务做切片
- 避免用 Promise.then 链式切片——错误未捕获易中断;也别用 setInterval 模拟分片,精度不可控且难管理状态
配套优化不做,拆了也白拆
拆分只是起点,这些轻量级动作决定效果上限:
- DOM 批量更新统一走 DocumentFragment,避免反复触发 layout;不用 innerHTML = htmlStr,改用 element.append()
- 位置计算尽量前置并缓存,禁止在循环中读写 offsetTop、getComputedStyle 等触发重排的属性
- 交互监听器延迟绑定:按钮、拖拽事件等,等节点进入视口后再用 IntersectionObserver 初始化,减少初始挂载负担
- 状态必须可续:所有分片函数都要记录断点(如 startIndex)、中间结果、中断标志,存在闭包或对象里,别依赖局部变量重置
不复杂但容易忽略。



















