当前位置: 首页 > news >正文

给一个学校网站做宣传海报衡阳有线宽带网站

给一个学校网站做宣传海报,衡阳有线宽带网站,如果做网站赚钱,网络营销竞价推广文章目录 背景时间切片原理requestIderCallback 方法setImmediateMessageChannelsetTimeout React 18 时间切片源码手撸时间切片问题拆解构建任务队列宏任务包装首次开启任务递归任务执行workLoop 开启工作循环demo 模拟 总结 背景 前文学习了 fiber 架构和双缓存技术#xff… 文章目录 背景时间切片原理requestIderCallback 方法setImmediateMessageChannelsetTimeout React 18 时间切片源码手撸时间切片问题拆解构建任务队列宏任务包装首次开启任务递归任务执行workLoop 开启工作循环demo 模拟 总结 背景 前文学习了 fiber 架构和双缓存技术接下来我们深入源码一起学习下时间切片的原理。 React 探秘(一)fiber 架构 React 探秘(二)双缓存技术 React 时间切片是 React 通过将任务分割成小的时间片然后分批次去处理任务在 js 线程繁忙的时候把控制权交还给浏览器本身如渲染进程等以提高应用程序性能的一种技术。本文将介绍 React v18.3.1 时间切片并提供一个简单的 demo以便开发者学习相关知识。 时间切片的主要优点 提高应用程序的响应性和流畅度分批次运行任务可以避免长时间占用 CPU。更好地控制渲染过程让用户可以快速看到应用程序的变化避免白屏等问题。 时间切片技术位置 fiber 架构的 Scheduler 调度器层。 Scheduler 分为两大部分 时间切片 异步渲染是优先级调度实现的前提优先级调度在异步渲染的基础上引入优先级机制控制任务的打断、替换。 本文只介绍时间切片相关内容 时间切片原理 时间切片的原理就是把我们一次性执行完的任务切分到不同时间间隔去完成如果超出这个时间间隔就会暂时挂起交给浏览器等到空闲了继续执行。那么问题就转化为如何实现给任务添加时间间隔 这里涉及到 js 事件循环机制同步代码宏任务-微任务-宏任务。 执行全局代码当 JavaScript 代码第一次运行时首先会执行同步代码相当于一次宏任务如果遇到微任务会把微任务方微任务队列遇到宏任务放入宏任务队列检查微任务队列一旦同步代码宏任务完成事件循环会检查并执行微任务队列中的所有任务直到队列为空。执行下一个宏任务如果微任务队列为空事件循环会从宏任务队列中取出下一个任务并执行。重复上述步骤这个过程会不断循环直到所有任务执行完毕。 宏任务会在下次事件循环中执行不会阻塞本次页面渲染更新。 微任务「微任务是在本次页面更新前会全部执行」这一点与同步执行无异不会让出主线程。 常见的宏任务方法有 setTimeoutmessageChannelsetImmediate 此外还有 requestIdleCallback 是在浏览器渲染后有空闲时间时执行。 requestIderCallback 方法 window.requestIdleCallback() 方法插入一个函数这个函数将在浏览器空闲时期被调用。这使开发者能够在主事件循环上执行后台和低优先级工作而不会影响延迟关键事件如动画和输入响应。函数一般会按先进先调用的顺序执行然而如果回调函数指定了执行超时时间 timeout则有可能为了在超时前执行函数而打乱执行顺序。 通过这个函数我们其实就可以时间一个简单的时间切片 function workLoop(deadline) {let shouldYield false;// 存在fiber并且时间空闲while (nextUnitOfWork !shouldYield) {nextUnitOfWork performUnitOfWork(nextUnitOfWork);shouldYield deadline.timeRemaining() 1; // 剩余时间是否小于1ms 代表任务繁忙}// 没有fiber并且wip存在if (!nextUnitOfWork workInProgress) {commitRoot();}// 繁忙时继续执行主任务requestIdleCallback(workLoop); }我们执行某个 fiberNode 的时候浏览器主线程被占用这个时候就可以暂停 fiberNode 的继续执行等浏览器空闲时继续 nextUnitOfWork。这就实现了可暂停可继续。但是呢这 api 有限制 requestIdleCallback 的执行时机不是完全可控的这可能导致在不同环境中表现不一致。requestIdleCallback 是利用帧之间空闲时间来执行 js它是一个低优先级的处理策略但实际上 fiber 的处理上并不算是一个低优先级任务。 setImmediate setImmediate 这个是最早执行的宏任务但是也可能会有兼容性问题。 MessageChannel MessageChannel 的执行时机比 setTimeout 靠前而且执行实际准确但是会有兼容性问题。 setTimeout setTimeout 执行时机在 messageChannel 之后如下 demo function workLoop() {setTimeout(() {nextUnitOfWork performUnitOfWork(nextUnitOfWork);workLoop()}, 0) }但是 setTimeout 的递归层级过深的话延迟就不是1ms而是4ms这样会造成延迟时间过长时间浪费。 看了上面这些方法多多少少都有些问题那么下面我们讲一下 react 怎么实现时间切片的。 React 18 时间切片源码 源码位置 https://github.com/facebook/react/blob/v18.3.1/packages/scheduler/src/forks/Scheduler.js 可以看到 react 18 中其实就是做了个兼容性判断 优先 setImmediate其次 messageChannel最后 setTimeout 直接看源码很容易懵逼因为源码中包含大量的兼容判断和优先级相关代码容易混淆我们的视线因此我们把复杂问题拆解一下从源码入手手撸一个 mini 版时间切片。 手撸时间切片 问题拆解 入口构建任务队列 创建时间切片通过当前时间 延迟得到过期时间塞入任务队列 创建宏任务 通过 setImmediate 等方法创建宏任务。 执行宏任务-循环执行时间切片 递归调用时间切片方法用于挂起、重启。 开启工作循环 循环执行队列任务超出时间不执行。 构建任务队列 使用 performance.now() 获取更精确的时间来创建每个任务过期时间并塞入任务队列中。 // 入口创建 task 并添加过期时间执行任务 function scheduleCallback(callbcak) {let unitOfwork {callbcak,expirationTime: performance.now() 5,}taskQueue.push(unitOfwork)// 开启宏任务requestHostCallback(workLoop) }宏任务包装 通过如下三个方法 localSetImmediate MessageChannel localSetTimeout 包装我们的 callback 为宏任务 // 把 performWorkUntilDeadline 方法放入宏任务当中 if (typeof localSetImmediate function) {schedulePerformWorkUntilDeadline () {localSetImmediate(performWorkUntilDeadline);}; } else if (typeof MessageChannel ! undefined) {const channel new MessageChannel();const port channel.port2;channel.port1.onmessage performWorkUntilDeadline;schedulePerformWorkUntilDeadline () {port.postMessage(null);}; } else {schedulePerformWorkUntilDeadline () {localSetTimeout(performWorkUntilDeadline, 0);}; } 首次开启任务 拿到当前正在处理的任务开启执行包装好的宏任务 function requestHostCallback(callback) {scheduledHostCallback callback;if (!isMessageLoopRunning) {isMessageLoopRunning true;schedulePerformWorkUntilDeadline();} }递归任务执行 执行宏任务获取当前时间,判断如果还有未完成的任务则开启递归。 // 宏任务执行的方法核心方法 const performWorkUntilDeadline () {if (scheduledHostCallback ! null) {const currentTime getCurrentTime();startTime currentTime;const hasTimeRemaining true;let hasMoreWork true;try {// 执行任务 scheduledHostCallback 就是 workLoophasMoreWork scheduledHostCallback(hasTimeRemaining, currentTime);} finally {if (hasMoreWork) {// 如果任务队列中还存在任务则继续递归执行schedulePerformWorkUntilDeadline();} else {isMessageLoopRunning false;scheduledHostCallback null;}}} else {isMessageLoopRunning false;} }; workLoop 开启工作循环 循环执行队列中的任务currentTask 为空结束循环判断时间是否过期过期则不执行任务把控制权还给浏览器。 function workLoop(hasTimeRemaining, initialTime) {let currentTime initialTime;currentTask peek(taskQueue);while (currentTask) {// 判断是时间是否过期if ((currentTask.expirationTime currentTime) (shouldYieldToHost() || !hasTimeRemaining)) {break} else {// 执行具体回调currentTask.callbcak()currentTask taskQueue.shift()// currentTask peek(taskQueue); // react 18 写法 包含小顶堆的排序算法}}// 还有剩余任务未执行完成返回 trueif (currentTask ! null) {return true;} else {return false;} }demo 模拟 下面使具体案例来模拟一下时间切片带来的改善: 完整版时间切片方法 let taskQueue [] // 任务队列 let isMessageLoopRunning false; // 标记 宏任务 正在运行 let scheduledHostCallback null; // 要执行的函数 workLoop let currentTask null; // 当前执行的任务 let startTime null; // 任务开始的时间const localSetTimeout typeof setTimeout function ? setTimeout : null; const localClearTimeout typeof clearTimeout function ? clearTimeout : null; const localSetImmediate typeof setImmediate ! undefined ? setImmediate : null;// 获取当前时间 const getCurrentTime () performance.now(); // 根据时间判断是否把控制权交给浏览器 function shouldYieldToHost() {const timeElapsed getCurrentTime() - startTime;if (timeElapsed 5) {return false;}return true; } // 获取数组第一项 function peek(heap) {return heap.length 0 ? null : heap[0]; } // 入口创建 task 并添加过期时间执行任务 function scheduleCallback(callbcak) {let unitOfwork {callbcak,expirationTime: performance.now() 5,}taskQueue.push(unitOfwork)// 开启宏任务requestHostCallback(workLoop) }// 宏任务执行的方法核心方法 const performWorkUntilDeadline () {if (scheduledHostCallback ! null) {const currentTime getCurrentTime();startTime currentTime;const hasTimeRemaining true;let hasMoreWork true;try {// 执行任务 scheduledHostCallback 就是 workLoophasMoreWork scheduledHostCallback(hasTimeRemaining, currentTime);} finally {if (hasMoreWork) {// 如果任务队列中还存在任务则继续递归执行schedulePerformWorkUntilDeadline();} else {isMessageLoopRunning false;scheduledHostCallback null;}}} else {isMessageLoopRunning false;} };// 把 performWorkUntilDeadline 方法放入宏任务当中 if (typeof localSetImmediate function) {schedulePerformWorkUntilDeadline () {localSetImmediate(performWorkUntilDeadline);}; } else if (typeof MessageChannel ! undefined) {const channel new MessageChannel();const port channel.port2;channel.port1.onmessage performWorkUntilDeadline;schedulePerformWorkUntilDeadline () {port.postMessage(null);}; } else {schedulePerformWorkUntilDeadline () {localSetTimeout(performWorkUntilDeadline, 0);}; }function requestHostCallback(callback) {scheduledHostCallback callback;if (!isMessageLoopRunning) {isMessageLoopRunning true;schedulePerformWorkUntilDeadline();} }function workLoop(hasTimeRemaining, initialTime) {let currentTime initialTime;currentTask peek(taskQueue);while (currentTask) {// 判断是时间是否过期if ((currentTask.expirationTime currentTime) (shouldYieldToHost() || !hasTimeRemaining)) {break} else {// 执行具体回调currentTask.callbcak()currentTask taskQueue.shift()// currentTask peek(taskQueue); // react 18 写法 包含小顶堆的排序算法}}// 还有剩余任务未执行完成返回 trueif (currentTask ! null) {return true;} else {return false;} }demo 模拟实现 let taskIndex 0; let taskTotal 5000; // 任务数量 const start Date.now();function handleTask() {for (let j 0; j 5000; j) {// 执行一些耗时操作const btn1Attr document.getElementById(btn1).attributes;const btn2Attr document.getElementById(btn2).attributes;const btn3Attr document.getElementById(btn3).attributes;}if(taskIndex taskTotal) {console.log(任务调度完成用时, Date.now() - start, ms!);} }while (taskIndex taskTotal) {scheduleCallback(handleTask) // 时间切片执行// handleTask() // 普通执行taskIndex }document.getElementById(btn1).onclick function () {console.log(11111, click) }// html bodydiv idrootbutton idbtn1按钮1/buttonbutton idbtn2按钮2/buttonbutton idbtn3按钮3/buttonbutton idbtn4按钮4/button/divscript src./sh.js/script /body 上面这一串代码在使用我们封装的 scheduleCallback 执行任务时dom 渲染几乎秒开但是如果使用普通的调用页面则会卡顿 3s 左右才会出现。 总结 react 使用时间切片提升渲染性能在熟知原理后同样我们在业务中也有很多优化场景可以使用到。例如高频埋点批量切片上传大量 dom 节点操作等等。
http://www.hkea.cn/news/14558039/

相关文章:

  • 沈阳大十字街附近做网站公司网站开发专业实习报告
  • 网站开发有什么用wordpress编辑导航栏
  • 企业网站怎么做seo优化网站建设网站定制开发
  • 怎么查看网站啥系统做的wordpress 餐饮订餐
  • 料远若近网站建设众筹网站哪家好
  • 怎样利用网站做自己的链接苏州新海通网站建设
  • 个人免费网站平台网站域名建设怎么填写
  • 网站keywords北京seo百度推广
  • 温州企业做网站广州网站建设定制方案
  • 网站左侧导航设计wordpress xml文件分割器
  • 网站背景色自己做一个简介的网页
  • 视频直播app开发网站织梦网站建设培训
  • 长沙商城网站制作网页前端开发框架
  • 淘宝客网站虚拟主机室内设计平面图分析
  • 做网站的公司市场网站首页页面代码
  • php搭建网站教程在线培训
  • 作弊网站网站开发技术网站模板
  • html5网站制作实战河南南阳油田网站建设
  • 蓬莱做网站公司深圳有做公司网站
  • 泉州建站服务wordpress 数据库 改ip
  • 建筑公司网站新年贺词网站美编设计怎么做
  • 什么是网站前置审批做网站需要干什么
  • 做网站注册商标哪一类建设网页建设
  • 7位数qq免费申请永久百度ocpc怎么优化
  • 网站开发报价单.doc头像制作软件app
  • 网站的ftp怎么查frontpage2003网页制作教程
  • 万网域名网站建设珠海市网站建设
  • 网站是哪个公司做可以发布广告的网站
  • ps做网站设计哪些网站是做数据分析的
  • 建设一个网站需要的空间有哪些方法中国做网站找谁