Day11--字节跳动-前端开发调试和性能优化之 PC 端调试|青训营

105 阅读7分钟

一、PC端

Bug与Debug

前端Debug的特点

  1. 多平台 浏览器、Hybrid、Node.js、小程序、桌面应用等
  2. 多环境 本地开发环境、线上环境
  3. 多工具 Chrome devTools、Charles、Spy-Debuggger、Whistle、vConsole...
  4. 多技巧 console、BreakPoint、sourceMap、代理等

Chrome DevTools

动态修改元素和样式

  • 点击.cls开启动态修改元素的class
  • 输入字符串可以动态的给元素添加类名
  • 勾选/取消类名可以动态的查看类名生效效果
  • 点击具体的样式值(字号、颜色、宽度高度等)可以进行编辑,浏览器内容区域实时预览
  • Computed下点击样式里的箭头可以跳转到styles面板中的css规则 可以用以下2种方式强制激活伪类
  • 选中具有伪类的元素,点击:hov
  • DOM树右键菜单,选择Force State

Console

  • console.log

  • console.warn

  • console.error

  • console.debug

  • console.info

  • console.table 具像化的展示JSON和数组数据

  • console.dir 通过类似文件树的方式展示对象的属性

  • 占位符 给日志添加样式,可以突出重要的信息 %s:字符串占位符;%o:对象占位符;%c:样式占位符;%d:数字

image.png

image.png

image.png

三、

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

移动端

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

优化策略

1. 减少重绘和重排

重绘和重排是由于 DOM 的变化而引起的浏览器重新渲染页面的操作,会消耗性能。以下是减少重绘和重排的一些方法:

  • 使用 CSS 合并: 尽量减少使用昂贵的 CSS 属性,如lefttopwidthheight 等,这些属性会引起重排和重绘。尽量使用 CSS3 的 transforms 和 transitions 来实现动画效果。
/* 不推荐的方式 */ 
element.style.left = newPosition + "px"; 
element.style.top = newPosition + "px"; 
/* 优化后的方式 */ 
element.style.transform = `translate(${newPosition}px, ${newPosition}px)`;
  • 批量 DOM 操作: 如果需要多次修改 DOM,最好将这些修改合并成一次操作,减少多次重绘和重排。
  • 使用文档片段: 使用文档片段(DocumentFragment)来批量添加 DOM 元素,然后一次性插入到文档中,减少页面的重新渲染。

当我们需要多次修改DOM时,将这些修改合并成一次操作可以显著减少多次的重绘和重排。下面是一个实例,我们将创建一个待办列表,并在多次添加任务时,将任务项合并成一次插入,以减少DOM操作。

    <h1>Todo List</h1>
    <input type="text" id="taskInput" placeholder="Enter a new task">
    <button id="addButton">Add Task</button>
    <ul id="taskList"></ul>

    <script>
        const taskInput = document.getElementById("taskInput");
        const addButton = document.getElementById("addButton");
        const taskList = document.getElementById("taskList");
        let tasks = [];

        // 添加任务到数组
        addButton.addEventListener("click", () => {
            const taskText = taskInput.value.trim();
            if (taskText !== "") {
                tasks.push(taskText);
                updateTaskList();
                taskInput.value = "";
            }
        });

        // 更新任务列表
        function updateTaskList() {
            // 创建文档片段
            const fragment = document.createDocumentFragment();

            // 创建任务项并添加到文档片段
            for (const taskText of tasks) {
                const li = document.createElement("li");
                li.textContent = taskText;
                fragment.appendChild(li);
            }

            // 清空任务列表并插入文档片段
            taskList.innerHTML = "";
            taskList.appendChild(fragment);
        }
    </script>

在这个示例中,每次点击"Add Task"按钮时,我们将任务文本添加到一个数组中,然后调用 updateTaskList 函数来更新任务列表。在 updateTaskList 函数中,我们首先创建一个文档片段,并在循环中创建任务项,并将它们添加到文档片段中。最后,我们一次性地清空任务列表并插入文档片段。这样做可以将多次的DOM操作合并成一次,从而减少了多次的重绘和重排,提高了性能。

2. 节流和防抖技术

这些技术有助于控制频繁触发的事件,从而减少不必要的函数执行,提高性能。

  • 节流(Throttling): 节流是限制函数的执行频率。例如,可以使用 setTimeout 来确保某个函数在一定的时间间隔内只执行一次。这对于如滚动、窗口调整等事件非常有用,以避免频繁的函数调用。
  • 防抖(Debouncing): 防抖是在事件被触发后等待一段时间,如果在这段时间内没有再次触发事件,则执行函数。这对于输入框实时搜索等场景非常有用,可以减少频繁的搜索请求。
// 节流函数
function throttle(func, delay) {
    let timeoutId;
    return function (...args) {
        if (!timeoutId) {
            timeoutId = setTimeout(() => {
                func.apply(this, args);
                timeoutId = null;
            }, delay);
        }
    };
}

// 使用节流
const throttledFunction = throttle(updatePosition, 100);
window.addEventListener("scroll", throttledFunction);

// 防抖
function debounce(func, delay) {
    let timeoutId;
    return function (...args) {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => {
            func.apply(this, args);
        }, delay);
    };
}

// 使用防抖
const debouncedFunction = debounce(searchFunction, 300);
inputField.addEventListener("input", debouncedFunction);

3. 使用性能分析工具

工具能够帮助您识别性能瓶颈和问题,从而进行针对性的优化。

  • 浏览器开发者工具: 浏览器自带的开发者工具(如 Chrome DevTools)提供了性能分析、内存分析、代码覆盖率等功能,可以帮助您分析代码的性能问题。详情请看这篇《前端开发调试》
  • Lighthouse: Lighthouse 是一个开源工具,可以对网页进行全面的性能分析,包括性能、可访问性、最佳实践等方面。
  • WebPageTest: WebPageTest 可以模拟不同网络条件下的页面加载情况,并提供详细的性能数据和建议。
  • 性能监控工具: 使用像 New RelicDatadogSentry 等性能监控工具,可以实时监测应用程序的性能,识别瓶颈并做出调整。

4. 懒加载和预加载

  • 懒加载(Lazy Loading): 对于页面上的图片、视频等资源,可以延迟加载,只有当用户滚动到相关区域时才加载,从而加快初始页面加载速度。

来看个例子:

<body>
    <div style="width: 100%; height: 600px;">
      <img data-src="img/image1.png" class="lazy-load-img" alt="Description">
    </div>
    <div style="width: 100%; height: 600px;">
    <img data-src="img/image2.png" class="lazy-load-img"  alt="Description">
    </div>
    <div style="width: 100%; height: 600px;">
    <img data-src="img/image3.png" class="lazy-load-img"  alt="Description">
    </div>
    <script>
      // 获取所有需要延迟加载的图片元素
      const lazyLoadImages = document.querySelectorAll('.lazy-load-img');
  
      // 触发加载函数
      function lazyLoad() {
          lazyLoadImages.forEach(img => {
              if (isElementInViewport(img) &&  !img.getAttribute('src')) {
                  img.setAttribute('src', img.getAttribute('data-src'));
                  img.classList.remove('lazy-load-img');
              }
          });
      }
  
      // 判断元素是否在可视区域内
      function isElementInViewport(el) {
          const rect = el.getBoundingClientRect();
          return (
              rect.bottom >= 0 &&
              rect.right >= 0 &&
              rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
              rect.left <= (window.innerWidth || document.documentElement.clientWidth)
          );
      }
  
      // 监听页面滚动事件
      window.addEventListener('scroll', lazyLoad);
      window.addEventListener('resize', lazyLoad);
      window.addEventListener('orientationchange', lazyLoad);
  
      // 初始加载一次以显示在视口内的图片
      lazyLoad();
  </script>
</body>

上述代码中,lazyLoad 函数会在滚动事件发生时判断图片是否进入可视区域,如果是则将 data-src 属性的值赋给 src 属性,实现图片加载。一旦加载完成,图片的类名也会从 lazy-load-img 移除,以免被重复加载。

因为可视区域内最多放置两张图片,所以刚开始就加载出了image1和image2!继续往下滚动就会加载第三张图片! image.png

  • 预加载(Preloading): 预加载可以在页面加载时提前加载一些可能会在将来使用的资源,例如,可以在页面中添加 <link rel="preload"> 标签来指示浏览器预加载资源。
<link rel="preload" href="image.jpg" as="image">

5. 优化网络请求

  • 使用缓存: 合理使用浏览器缓存,尽量减少重复的网络请求。
  1. 使用 Cache-Control 响应头 在服务器端设置适当的 Cache-Control 响应头来控制浏览器缓存行为。这可以告诉浏览器资源的缓存策略。
// 在服务器端设置 Cache-Control 响应头
// 例如,对于静态资源,可以设置 Cache-Control 为一周
// 在 Express.js 中的示例
app.use(express.static('public', { maxAge: 604800000 }));
  1. 使用版本号或哈希值作为资源路径

在前端,可以通过在资源路径中添加版本号或哈希值来防止缓存失效。

<!-- 使用版本号 -->
<link rel="stylesheet" href="styles.css?v=1.0">
<img src="image.jpg?v=1.0" alt="Cached Image">

<!-- 或使用哈希值 -->
<link rel="stylesheet" href="styles.a1b2c3d4.css">
<img src="image.x5y6z7w8.jpg" alt="Cached Image">
  • 减少请求次数: 合并 CSS 和 JavaScript 文件,减少请求次数,使用雪碧图或 SVG 图标来减少图片请求。
// index.html
<link rel="stylesheet" href="styles.css">
<script src="script.js"></script>

在这个示例中,styles.cssscript.js 文件都是通过 <link><script> 标签引入的。在实际项目中,可以使用构建工具(如Webpack)来将多个 CSS 和 JavaScript 文件合并成一个,从而减少页面的请求次数。

  • 使用 CDN: 使用内容分发网络(CDN)可以加速资源加载,将内容分发到全球多个节点。

例子:假设我有一个网站,需要加载一个名为 script.js 的 JavaScript 文件。首先,将该文件上传到一个 CDN 提供商(例如,CloudflareAmazon CloudFront 等)。然后,通过修改网页中的链接来使用 CDN 提供的资源。

<body>
    <h1>Using CDN Example</h1>
    <!-- 使用 CDN 提供的资源链接 -->
    <script src="https://cdn.example.com/script.js"></script>
</body>

在这个示例中,https://cdn.example.com 是自己上传 script.js 文件的 CDN 地址。通过使用 CDN 提供的链接,浏览器会从距离用户最近的节点加载资源,从而减少加载时间。