操屁眼的视频在线免费看,日本在线综合一区二区,久久在线观看免费视频,欧美日韩精品久久综

新聞資訊

    信使用iPhone、iPad等蘋果設備的用戶,對于“刷機”這個操作詞有所了解。


    忘記鎖屏、白蘋果、莫名黑屏、自動重啟等設備故障時,去維修店也會建議進行刷機操作。





    但蘋果刷機其實十分簡單,自己在家就能輕松完成。


    今天小編就來告訴你,從選擇工具,注意事項,到完成刷機的整個流程。







    一、iPhone刷機工具有哪些?


    蘋果刷機工具可以分成兩種,蘋果官方iTunes和其它第三方工具,市面上如愛思、牛學長等。



    iTunes:蘋果官方數據管理工具,可以進行刷機操作,但是操作相對繁雜,出現報錯1100、4013、1110、75等問題較多,失敗率較高。





    其它三方工具:操作簡單,小白也能輕松掌握,相對成功率更高。







    二、刷機前的注意事項?


    1、頻繁刷機容易對手機硬件產生負面影響,手機壽命會降低;


    2、刷機操作存在導致設備變磚的風險,借助專業的刷機工具風險較低;


    3、如果設備開啟了【查找】或此AppleID登錄iCloud,將會出現激活鎖,提前準備好AppleID賬號和密碼。






    4、提前做好數據備份。刷機是會徹底清除設備數據的,能正常使用的設備一定要提前做好數據備份。


    蘋果數據備份,可以使用iTunes一鍵整機數據備份和恢復,也可以使用牛學長蘋果數據管理工具,選擇性備份和恢復需要的數據。










    三、刷機能解決哪些問題?


    無論是iPhone或iPad,刷機只能解決設備出現的iOS系統故障,包括白蘋果、黑屏、不停重啟、卡在恢復模式、更新失敗、無法開機等iOS系統問題。


    如果是因為摔落、擠壓、浸水、電池老化等造成的硬件故障,是無法通過刷機進行解決的。










    四、如何正確刷機?


    首先,在刷機前需要準備的工具:


    1、Win或Mac電腦均可,下載安裝好刷機工具


    2、蘋果數據線(原裝最佳)


    3、需要進行刷機的iPhone



    這里以操作簡單、小白適用的牛學長蘋果手機修復工具為例,其修復功能可減少刷機系統故障,這里演示刷機操作的整個流程。




    操作指引:


    第1步:下載安裝好刷機工具,通過數據線連接iPhone與電腦,軟件識別成功后,點擊“修復iOS系統問題”,選擇“深度修復”模式即可。





    當設備處于黑屏、白蘋果等狀態,軟件無法正常識別時,點擊“修復iOS系統問題”后,軟件將會提示將設備進入恢復模式/DFU模式




    第2步:待軟件成功識別設備后,再點擊“下載固件”。


    下載成功后即可開始刷機操作,注意不要斷開數據線,整個過程大概需要10分鐘,等待顯示“修復完成”即可。





    第3步:刷機成功。


    如果設備只是出現白蘋果、卡在恢復模式、莫名黑屏、自動重啟等iOS系統故障,同時想保留數據,那么可先使用“標準修復”來修復系統,不會丟失設備數據,成功率80%左右。





    /////



    關于蘋果刷機,你是否還存在其它疑問呢?


    在評論區留言,牛學長為你在線解答!







    更多精彩閱讀:

    • 「iOS15」蘋果手機怎么錄屏?iPhone錄制視頻沒聲音怎么辦?
    • “查找我的iPhone”有什么用?iOS15「查找」8大功能詳解
    • 蘋果iPhone白屏了,長按電源鍵無反應怎么修復?
    • iPhone其他系統內存占了30G+,怎么清理?
    • apple pay無法添加銀行卡,終于找到解決方法了
    • U盤壞了數據可以恢復嗎?超詳細小白圖文教程

    提升首屏的加載速度,是前端性能優化中最重要的環節,這里筆者梳理出一些 常規且有效 的首屏優化建議

    目標: 通過對比優化前后的性能變化,來驗證方案的有效性,了解并掌握其原理

    1、路由懶加載

    SPA 項目,一個路由對應一個頁面,如果不做處理,項目打包后,會把所有頁面打包成一個文件,當用戶打開首頁時,會一次性加載所有的資源,造成首頁加載很慢,降低用戶體驗

    列一個實際項目的打包詳情:

    • app.js 初始體積: 1175 KB
    • app.css 初始體積: 274 KB

    將路由全部改成懶加載

    // 通過webpackChunkName設置分割后代碼塊的名字
    const Home = () => import(/* webpackChunkName: "home" */ "@/views/home/index.vue");
    const MetricGroup = () => import(/* webpackChunkName: "metricGroup" */ "@/views/metricGroup/index.vue");
    …………
    const routes = [
        {
           path: "/",
           name: "home",
           component: Home
        },
        {
           path: "/metricGroup",
           name: "metricGroup",
           component: MetricGroup
        },
        …………
     ]
    復制代碼

    重新打包后,首頁資源拆分為 app.js 和 home.js,以及對應的 css 文件

    • app.js:244 KB、 home.js: 35KB
    • app.css:67 KB、home.css: 15KB

    通過路由懶加載,該項目的首頁資源壓縮約 52%

    路由懶加載的原理

    懶加載前提的實現:ES6的動態地加載模塊——import()

    調用 import() 之處,被作為分離的模塊起點,意思是,被請求的模塊和它引用的所有子模塊,會分離到一個單獨的 chunk 中
    ——摘自《webpack——模塊方法》的import()小節

    要實現懶加載,就得先將進行懶加載的子模塊分離出來,打包成一個單獨的文件

    webpackChunkName 作用是 webpack 在打包的時候,對異步引入的庫代碼(lodash)進行代碼分割時,設置代碼塊的名字。webpack 會將任何一個異步模塊與相同的塊名稱組合到相同的異步塊中

    2、組件懶加載

    除了路由的懶加載外,組件的懶加載在很多場景下也有重要的作用

    舉個:

    home 頁面 和 about 頁面,都引入了 dialogInfo 彈框組件,該彈框不是一進入頁面就加載,而是需要用戶手動觸發后才展示出來

    home 頁面示例:

    <template>
      <div class="homeView">
        <p>home 頁面</p>
        <el-button @click="dialogVisible = !dialogVisible">打開彈框</el-button>
        <dialogInfo v-if="dialogVisible" />
      </div>
    </template>
    <script>
    import dialogInfo from '@/components/dialogInfo';
    export default {
      name: 'homeView',
      components: {
        dialogInfo
      }
    }
    </script>
    復制代碼

    項目打包后,發現 home.js 和 about.js 均包括了該彈框組件的代碼(在 dist 文件中搜索dialogInfo彈框組件)

    當用戶打開 home 頁時,會一次性加載該頁面所有的資源,我們期望的是用戶觸發按鈕后,再加載該彈框組件的資源

    這種場景下,就很適合用懶加載的方式引入

    彈框組件懶加載:

    <script>
    const dialogInfo = () => import(/* webpackChunkName: "dialogInfo" */ '@/components/dialogInfo');
    export default {
      name: 'homeView',
      components: {
        dialogInfo
      }
    }
    </script>
    復制代碼

    重新打包后,home.js 和 about.js 中沒有了彈框組件的代碼,該組件被獨立打包成 dialogInfo.js,當用戶點擊按鈕時,才會去加載 dialogInfo.js 和 dialogInfo.css

    最終,使用組件路由懶后,該項目的首頁資源進一步減少約 11%

    組件懶加載的使用場景

    有時資源拆分的過細也不好,可能會造成瀏覽器 http 請求的增多

    總結出三種適合組件懶加載的場景:

    1)該頁面的 JS 文件體積大,導致頁面打開慢,可以通過組件懶加載進行資源拆分,利用瀏覽器并行下載資源,提升下載速度(比如首頁)

    2)該組件不是一進入頁面就展示,需要一定條件下才觸發(比如彈框組件)

    3)該組件復用性高,很多頁面都有引入,利用組件懶加載抽離出該組件,一方面可以很好利用緩存,同時也可以減少頁面的 JS 文件大小(比如表格組件、圖形組件等)

    3、合理使用 Tree shaking

    Tree shaking 的作用:消除無用的 JS 代碼,減少代碼體積

    舉個:

    // util.js
    export function targetType(target) {
      return Object.prototype.toString.call(target).slice(8, -1).toLowerCase();
    }
    export function deepClone(target) {
      return JSON.parse(JSON.stringify(target));
    }
    復制代碼

    項目中只使用了 targetType 方法,但未使用 deepClone 方法,項目打包后,deepClone 方法不會被打包到項目里

    tree-shaking 原理:

    依賴于ES6的模塊特性,ES6模塊依賴關系是確定的,和運行時的狀態無關,可以進行可靠的靜態分析,這就是 tree-shaking 的基礎

    靜態分析就是不需要執行代碼,就可以從字面量上對代碼進行分析。ES6之前的模塊化,比如 CommonJS 是動態加載,只有執行后才知道引用的什么模塊,就不能通過靜態分析去做優化,正是基于這個基礎上,才使得 tree-shaking 成為可能

    Tree shaking 并不是萬能的

    并不是說所有無用的代碼都可以被消除,還是上面的代碼,換個寫法 tree-shaking 就失效了

    // util.js
    export default {
      targetType(target) {
        return Object.prototype.toString.call(target).slice(8, -1).toLowerCase();
      },
      deepClone(target) {
        return JSON.parse(JSON.stringify(target));
      }
    };
    
    // 引入并使用
    import util from '../util';
    util.targetType(null)
    復制代碼

    同樣的,項目中只使用了 targetType 方法,未使用 deepClone 方法,項目打包后,deepClone 方法還是被打包到項目里

    在 dist 文件中搜索 deepClone 方法:

    究其原因,export default 導出的是一個對象,無法通過靜態分析判斷出一個對象的哪些變量未被使用,所以 tree-shaking 只對使用 export 導出的變量生效

    這也是函數式編程越來越火的原因,因為可以很好利用 tree-shaking 精簡項目的體積,也是 vue3 全面擁抱了函數式編程的原因之一

    4、骨架屏優化白屏時長

    使用骨架屏,可以縮短白屏時間,提升用戶體驗。國內大多數的主流網站都使用了骨架屏,特別是手機端的項目

    SPA 單頁應用,無論 vue 還是 react,最初的 html 都是空白的,需要通過加載 JS 將內容掛載到根節點上,這套機制的副作用:會造成長時間的白屏

    常見的骨架屏插件就是基于這種原理,在項目打包時將骨架屏的內容直接放到 html 文件的根節點中

    使用骨架屏插件,打包后的 html 文件(根節點內部為骨架屏):

    同一項目,對比使用骨架屏前后的 FP 白屏時間:

    • 無骨架屏:白屏時間 1063ms
    • 有骨架屏:白屏時間 144ms

    骨架屏確實是優化白屏的不二選擇,白屏時間縮短了 86%

    骨架屏插件

    這里以 vue-skeleton-webpack-plugin 插件為例,該插件的亮點是可以給不同的頁面設置不同的骨架屏,這點確實很酷

    1)安裝

    npm i vue-skeleton-webpack-plugin 
    復制代碼

    2)vue.config.js 配置

    // 骨架屏
    const SkeletonWebpackPlugin = require("vue-skeleton-webpack-plugin");
    module.exports = {
       configureWebpack: {
          plugins: [
           new SkeletonWebpackPlugin({
            // 實例化插件對象
            webpackConfig: {
              entry: {
                app: path.join(__dirname, './src/skeleton.js') // 引入骨架屏入口文件
              }
            },
            minimize: true, // SPA 下是否需要壓縮注入 HTML 的 JS 代碼
            quiet: true, // 在服務端渲染時是否需要輸出信息到控制臺
            router: {
              mode: 'hash', // 路由模式
              routes: [
                // 不同頁面可以配置不同骨架屏
                // 對應路徑所需要的骨架屏組件id,id的定義在入口文件內
                { path: /^\/home(?:\/)?/i, skeletonId: 'homeSkeleton' },
                { path: /^\/detail(?:\/)?/i, skeletonId: 'detailSkeleton' }
              ]
            }
          })        
          ]
       }
    }
    復制代碼

    3)新建 skeleton.js 入口文件

    // skeleton.js
    import Vue from "vue";
    // 引入對應的骨架屏頁面
    import homeSkeleton from "./views/homeSkeleton";
    import detailSkeleton from "./views/detailSkeleton";
    
    export default new Vue({
        components: {
            homeSkeleton,
            detailSkeleton,
        },
        template: `
        <div>
          <homeSkeleton id="homeSkeleton" style="display:none;" />
          <detailSkeleton id="detailSkeleton" style="display:none;" />
        </div>
      `,
    });
    復制代碼

    5、長列表虛擬滾動

    首頁中不乏有需要渲染長列表的場景,當渲染條數過多時,所需要的渲染時間會很長,滾動時還會造成頁面卡頓,整體體驗非常不好

    虛擬滾動——指的是只渲染可視區域的列表項,非可見區域的不渲染,在滾動時動態更新可視區域,該方案在優化大量數據渲染時效果是很明顯的

    虛擬滾動圖例:

    虛擬滾動基本原理:

    計算出 totalHeight 列表總高度,并在觸發時滾動事件時根據 scrollTop 值不斷更新 startIndex 以及 endIndex ,以此從列表數據 listData 中截取對應元素

    虛擬滾動性能對比:

    • 在不使用虛擬滾動的情況下,渲染10萬個文本節點:
    • 使用虛擬滾動的情況后:

    使用虛擬滾動使性能提升了 78%

    虛擬滾動插件

    虛擬滾動的插件有很多,比如 vue-virtual-scroller、vue-virtual-scroll-list、react-tiny-virtual-list、react-virtualized 等

    這里簡單介紹 vue-virtual-scroller 的使用

    // 安裝插件
    npm install vue-virtual-scroller
    
    // main.js
    import VueVirtualScroller from 'vue-virtual-scroller'
    import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
    
    Vue.use(VueVirtualScroller)
    
    // 使用
    <template> 
      <RecycleScroller 
        class="scroller" 
        :items="list" 
        :item-size="32" 
        key-field="id" 
        v-slot="{ item }"> 
          <div class="user"> {{ item.name }} </div>
      </RecycleScroller> 
    </template>
    復制代碼

    該插件主要有 RecycleScroller.vue、DynamicScroller.vue 這兩個組件,其中 RecycleScroller 需要 item 的高度為靜態的,也就是列表每個 item 的高度都是一致的,而 DynamicScroller 可以兼容 item 的高度為動態的情況

    6、Web Worker 優化長任務

    由于瀏覽器 GUI 渲染線程與 JS 引擎線程是互斥的關系,當頁面中有很多長任務時,會造成頁面 UI 阻塞,出現界面卡頓、掉幀等情況

    查看頁面的長任務:

    打開控制臺,選擇 Performance 工具,點擊 Start 按鈕,展開 Main 選項,會發現有很多紅色的三角,這些就屬于長任務(長任務:執行時間超過50ms的任務)

    測試實驗:

    如果直接把下面這段代碼直接丟到主線程中,計算過程中頁面一直處于卡死狀態,無法操作

    let sum = 0;
    for (let i = 0; i < 200000; i++) {
        for (let i = 0; i < 10000; i++) {
          sum += Math.random()
        }
      }
    復制代碼

    使用 Web Worker 執行上述代碼時,計算過程中頁面正常可操作、無卡頓

    // worker.js
    onmessage = function (e) {
      // onmessage獲取傳入的初始值
      let sum = e.data;
      for (let i = 0; i < 200000; i++) {
        for (let i = 0; i < 10000; i++) {
          sum += Math.random()
        }
      }
      // 將計算的結果傳遞出去
      postMessage(sum);
    }
    復制代碼

    Web Worker 具體的使用與案例,詳情見 一文徹底了解Web Worker,十萬、百萬條數據都是弟弟

    Web Worker 的通信時長

    并不是執行時間超過 50ms 的任務,就可以使用 Web Worker,還要先考慮通信時長的問題

    假如一個運算執行時長為 100ms,但是通信時長為 300ms, 用了 Web Worker可能會更慢

    比如新建一個 web worker, 瀏覽器會加載對應的 worker.js 資源,下圖中的 Time 是這個資源的通信時長(也叫加載時長)

    當任務的運算時長 - 通信時長 > 50ms,推薦使用Web Worker

    7、requestAnimationFrame 制作動畫

    requestAnimationFrame 是瀏覽器專門為動畫提供的 API,它的刷新頻率與顯示器的頻率保持一致,使用該 api 可以解決用 setTimeout/setInterval 制作動畫卡頓的情況

    下面的案例演示了兩者制作進度條的對比(運行按鈕可點擊)

    可以看到使用定時器制作的動畫,卡頓還是比較明顯的

    setTimeout/setInterval、requestAnimationFrame 三者的區別:

    1)引擎層面

    setTimeout/setInterval 屬于 JS引擎,requestAnimationFrame 屬于 GUI引擎

    JS引擎與GUI引擎是互斥的,也就是說 GUI 引擎在渲染時會阻塞 JS 引擎的計算

    2)時間是否準確

    requestAnimationFrame 刷新頻率是固定且準確的,但 setTimeout/setInterval 是宏任務,根據事件輪詢機制,其他任務會阻塞或延遲js任務的執行,會出現定時器不準的情況

    3)性能層面

    當頁面被隱藏或最小化時,setTimeout/setInterval 定時器仍會在后臺執行動畫任務,而使用 requestAnimationFrame 當頁面處于未激活的狀態下,屏幕刷新任務會被系統暫停

    8、JS 的6種加載方式

    1)正常模式

    <script src="index.js"></script>
    復制代碼

    這種情況下 JS 會阻塞 dom 渲染,瀏覽器必須等待 index.js 加載和執行完成后才能去做其它事情

    2)async 模式

    <script async src="index.js"></script>
    復制代碼

    async 模式下,它的加載是異步的,JS 不會阻塞 DOM 的渲染,async 加載是無順序的,當它加載結束,JS 會立即執行

    使用場景:若該 JS 資源與 DOM 元素沒有依賴關系,也不會產生其他資源所需要的數據時,可以使用async 模式,比如埋點統計

    3)defer 模式

    <script defer src="index.js"></script>
    復制代碼

    defer 模式下,JS 的加載也是異步的,defer 資源會在 DOMContentLoaded 執行之前,并且 defer 是有順序的加載

    如果有多個設置了 defer 的 script 標簽存在,則會按照引入的前后順序執行,即便是后面的 script 資源先返回

    所以 defer 可以用來控制 JS 文件的執行順序,比如 element-ui.js 和 vue.js,因為 element-ui.js 依賴于 vue,所以必須先引入 vue.js,再引入 element-ui.js

    <script defer src="vue.js"></script>
    <script defer src="element-ui.js"></script>
    復制代碼

    defer 使用場景:一般情況下都可以使用 defer,特別是需要控制資源加載順序時

    4)module 模式

    <script type="module">import { a } from './a.js'</script>
    復制代碼

    在主流的現代瀏覽器中,script 標簽的屬性可以加上 type="module",瀏覽器會對其內部的 import 引用發起 HTTP 請求,獲取模塊內容。這時 script 的行為會像是 defer 一樣,在后臺下載,并且等待 DOM 解析

    Vite 就是利用瀏覽器支持原生的 es module 模塊,開發時跳過打包的過程,提升編譯效率

    5) preload

    <link rel="preload" as="script" href="index.js">
    復制代碼

    link 標簽的 preload 屬性:用于提前加載一些需要的依賴,這些資源會優先加載(如下圖紅框)

    vue2 項目打包生成的 index.html 文件,會自動給首頁所需要的資源,全部添加 preload,實現關鍵資源的提前加載

    preload 特點:

    1)preload 加載的資源是在瀏覽器渲染機制之前進行處理的,并且不會阻塞 onload 事件;

    2)preload 加載的 JS 腳本其加載和執行的過程是分離的,即 preload 會預加載相應的腳本代碼,待到需要時自行調用;

    6)prefetch

    <link rel="prefetch" as="script" href="index.js">
    復制代碼

    prefetch 是利用瀏覽器的空閑時間,加載頁面將來可能用到的資源的一種機制;通常可以用于加載其他頁面(非首頁)所需要的資源,以便加快后續頁面的打開速度

    prefetch 特點:

    1)pretch 加載的資源可以獲取非當前頁面所需要的資源,并且將其放入緩存至少5分鐘(無論資源是否可以緩存)

    2)當頁面跳轉時,未完成的 prefetch 請求不會被中斷

    加載方式總結

    async、defer 是 script 標簽的專屬屬性,對于網頁中的其他資源,可以通過 link 的 preload、prefetch 屬性來預加載

    如今現代框架已經將 preload、prefetch 添加到打包流程中了,通過靈活的配置,去使用這些預加載功能,同時我們也可以審時度勢地向 script 標簽添加 async、defer 屬性去處理資源,這樣可以顯著提升性能

    9、圖片的優化

    平常大部分性能優化工作都集中在 JS 方面,但圖片也是頁面上非常重要的部分

    特別是對于移動端來說,完全沒有必要去加載原圖,浪費帶寬。如何去壓縮圖片,讓圖片更快的展示出來,有很多優化工作可以做

    淘寶首頁的圖片資源都很小:

    圖片的動態裁剪

    很多云服務,比如阿里云或七牛云,都提供了圖片的動態裁剪功能,效果很棒,確實是錢沒有白花

    只需在圖片的url地址上動態添加參數,就可以得到你所需要的尺寸大小,比如:http://7xkv1q.com1.z0.glb.clouddn.com/grape.jpg?imageView2/1/w/200/h/200

    圖片瘦身前后對比:

    • 原圖:1.8M
    • 裁剪后:12.8KB

    經過動態裁剪后的圖片,加載速度會有非常明顯的提升

    圖片的懶加載

    對于一些圖片量比較大的首頁,用戶打開頁面后,只需要呈現出在屏幕可視區域內的圖片,當用戶滑動頁面時,再去加載出現在屏幕內的圖片,以優化圖片的加載效果

    圖片懶加載實現原理:

    由于瀏覽器會自動對頁面中的 img 標簽的 src 屬性發送請求并下載圖片,可以通過 html5 自定義屬性 data-xxx 先暫存 src 的值,然后在圖片出現在屏幕可視區域的時候,再將 data-xxx 的值重新賦值到 img 的 src 屬性即可

    <img src="" alt="" data-src="./images/1.jpg">
    <img src="" alt="" data-src="./images/2.jpg">
    復制代碼

    這里以 vue-lazyload 插件為例

    // 安裝 
    npm install vue-lazyload 
        
    // main.js 注冊
    import VueLazyload from 'vue-lazyload'
    Vue.use(VueLazyload)
    // 配置項
    Vue.use(VueLazyload, {
      preLoad: 1.3,
      error: 'dist/error.png', // 圖片加載失敗時的占位圖
      loading: 'dist/loading.gif', // 圖片加載中時的占位圖
      attempt: 1
    })
    
    // 通過 v-lazy 指令使用
    <ul>  
        <li v-for="img in list">
            <img v-lazy="img.src" :key="img.src" >
        </li>
    </ul>
    復制代碼

    使用字體圖標

    字體圖標是頁面使用小圖標的不二選擇,最常用的就是 iconfont

    字體圖標的優點:

    1)輕量級:一個圖標字體要比一系列的圖像要小。一旦字體加載了,圖標就會馬上渲染出來,減少了 http 請求

    2)靈活性:可以隨意的改變顏色、產生陰影、透明效果、旋轉等

    3)兼容性:幾乎支持所有的瀏覽器,請放心使用

    圖片轉 base64 格式

    將小圖片轉換為 base64 編碼字符串,并寫入 HTML 或者 CSS 中,減少 http 請求

    轉 base64 格式的優缺點:

    1)它處理的往往是非常小的圖片,因為 Base64 編碼后,圖片大小會膨脹為原文件的 4/3,如果對大圖也使用 Base64 編碼,后者的體積會明顯增加,即便減少了 http 請求,也無法彌補這龐大的體積帶來的性能開銷,得不償失

    2)在傳輸非常小的圖片的時候,Base64 帶來的文件體積膨脹、以及瀏覽器解析 Base64 的時間開銷,與它節省掉的 http 請求開銷相比,可以忽略不計,這時候才能真正體現出它在性能方面的優勢

    項目可以使用 url-loader 將圖片轉 base64:

    // 安裝
    npm install url-loader --save-dev
        
    // 配置
    module.exports = {
      module: {
        rules: [{
            test: /.(png|jpg|gif)$/i,
            use: [{
                loader: 'url-loader',
                options: {
                  // 小于 10kb 的圖片轉化為 base64
                  limit: 1024 * 10
                }
            }]
         }]
      }
    };
    復制代碼

    關于前端性能優化的知識點

    “春江水暖鴨先知,產品好壞客戶知”,作為前端開發,我們更注重客戶體驗,產品的好壞決定著客戶的體驗,那么一款產品的好壞有很多因素,其中性能是決定因素,那么怎么優化才能讓產品的性能達到優良,讓客戶體驗良好,今天我就帶大家去了解學習前端性能優化

    優化的目的

    優化的目的在于讓頁面加載的更快,對用戶操作響應更及時,為用戶帶來更好的用戶體驗,對于開發者來說優化能夠減少頁面請求數,能夠節省資源。

    前端優化的方法有很多種,可以將其分為兩大類,第一類是頁面級別的優化如http請求數,內聯腳本的位置優化等,第二類為代碼級別的優化,例Javascript中的DOM 操作優化、CSS選擇符優化、圖片優化以及 HTML結構優化等等。

    優化哪些?

    那么我們需要優化哪些點呢?

    1. 加載資源優化
    2. 渲染優化
    3. 瀏覽器緩存策略
    4. 圖片優化
    5. 節流與防抖

    加載資源優化

    說起加載,當我們輸入URL時,我們要知道這中間發生了什么?

    • 首先做 DNS 查詢,如果這一步做了智能 DNS 解析的話,會提供訪問速度最快的 IP 地址回來
    • 接下來是 TCP 握手,應用層會下發數據給傳輸層,這里 TCP 協議會指明兩端的端口號,然后下發給網絡層。網絡層中的 IP 協議會確定 IP 地址,并且指示了數據傳輸中如何跳轉路由器。然后包會再被封裝到數據鏈路層的數據幀結構中,最后就是物理層面的傳輸了
    • TCP 握手結束后會進行 TLS 握手,然后就開始正式的傳輸數據
    • 數據在進入服務端之前,可能還會先經過負責負載均衡的服務器,它的作用就是將請求合理的分發到多臺服務器上,這時假設服務端會響應一個 HTML 文件
    • 首先瀏覽器會判斷狀態碼是什么,如果是 200 那就繼續解析,如果 400 或 500 的話就會報錯,如果 300 的話會進行重定向,這里會有個重定向計數器,避免過多次的重定向,超過次數也會報錯
    • 瀏覽器開始解析文件,如果是 gzip 格式的話會先解壓一下,然后通過文件的編碼格式知道該如何去解碼文件
    • 文件解碼成功后會正式開始渲染流程,先會根據 HTML 構建 DOM 樹,有 CSS 的話會去構建 CSSOM 樹。如果遇到 script 標簽的話,會判斷是否存在 async 或者 defer ,前者會并行進行下載并執行 JS,后者會先下載文件,然后等待 HTML 解析完成后順序執行,如果以上都沒有,就會阻塞住渲染流程直到 JS 執行完畢。遇到文件下載的會去下載文件,這里如果使用 HTTP 2.0 協議的話會極大的提高多圖的下載效率。
    • 初始的 HTML 被完全加載和解析后會觸發 DOMContentLoaded 事件
    • CSSOM 樹和 DOM 樹構建完成后會開始生成 Render 樹,這一步就是確定頁面元素的布局、樣式等等諸多方面的東西
    • 在生成 Render 樹的過程中,瀏覽器就開始調用 GPU 繪制,合成圖層,將內容顯示在屏幕上了

    我們從輸入 URL 到顯示頁面這個過程中,涉及到網絡層面的,有三個主要過程:

    • DNS 解析
    • TCP 連接
    • HTTP 請求/響應

    這里我們就不用去管DNS解析和TCP鏈接了,畢竟不是我們的事,也干不來,但是HTTP請求和響應是我們優化的重點。

    HTTP優化可分為兩個方面:

    • 盡量減少請求次數
    • 盡量減少單次請求所花費的時間

    減少請求數:

    • 合理的設置http緩存,恰當的緩存設置可以大大減少http請求。要盡可能地讓資源能夠在緩存中待得更久。
    • 從設計實現層面簡化頁面,保持頁面簡潔、減少資源的使用時是最直接的。
    • 資源合并與壓縮,盡可能的將外部的腳本、樣式進行合并,多個合為一個。
    • CSS Sprites,通過合并 CSS圖片,這是減少請求數的一個好辦法

    內聯腳本的位置:

    瀏覽器是并發請求的,很多時候我們會加入很多的外鏈腳本,而外鏈腳本在加載時卻常常阻塞其他資源,例如在腳本加載完成之前,它后面的圖片、樣式以及其他腳本都處于阻塞狀態,直到腳本加載完成后才會開始加載。如果將腳本放在比較靠前的位置,則會影響整個頁面的加載速度從而影響用戶體驗。所以說盡可能的將腳本往后挪,減少對并發下載的影響。

    渲染優化

    客戶端的渲染

    前端去取后端的數據生成DOM樹,加載過來后,自己在瀏覽器由上而下跑執行JS,隨后就會生成相應的DOM。

    優點:

    1. 客戶端的渲染使得前后端分離,開發效率高
    2. 用戶體驗更好,我們將網站做成SPA(單頁面應用)或者部分內容做成SPA,當用戶點擊時,不會形成頻繁的跳轉

    缺點:

    1. 前端響應速度慢,特別是首屏,這樣用戶是受不了的
    2. 不利于SEO優化,因為爬蟲不認識SPA,所以它只是記錄了一個頁面

    服務端的渲染

    DOM樹在服務端生成,然后返回給前端,頁面上展現的內容,我們在HTML源文件也能找到。

    優點:

    1. 服務端渲染盡量不占用前端的資源,前端這塊耗時少,速度快
    2. 利于SEO優化,因為在后端有完整的html頁面,所以爬蟲更容易爬取信息

    缺點:

    1. 不利于前后端分離,開發的效率降低了
    2. 對html的解析,對前端來說加快了速度,但是加大了服務器的壓力

    類似企業級網站,主要功能是頁面展示,它沒有復雜的交互,并且需要良好的SEO,那我們應該使用服務端渲染。

    現在很多網站使用服務端渲染和客戶端渲染結合的方式:首屏使用服務端渲染,其他頁面使用客戶端渲染。這樣可以保證首屏的加載速度,也完成了前后端分離。

    區分:源碼里如果能找到前端頁面中的內容文字,那就是在服務端構建的DOM,就是服務端渲染,反之是客戶端渲染。

    瀏覽器渲染

    瀏覽器渲染機制一般分為:

    • 分析HTML并構建DOM樹
    • 分析CSS構建CSSOM樹
    • 將DOM和CSSOM合并成一個渲染樹
    • 根據渲染樹布局,計算每個節點的位置
    • 調用GPU繪制,合成圖層,顯示頁面

    在渲染DOM的時候,瀏覽器所做的事情:

    • 獲取DOM后分割為多個圖層
    • 對每個圖層的節點計算樣式結果(recalculate style -- 樣式重計算)
    • 為每個節點生成圖形和位置(layout -- 回流和重布局)
    • 將每個節點繪制填充到圖層位圖中(paint setup 和 paint -- 重繪)
    • 圖層作為紋理上傳至GPU
    • 復合多個圖層到頁面上生成最終屏幕圖像(composite layers -- 圖層重組)

    新建獨立圖層會減少重回回流帶來的影響,但是在圖層重組的時候會消耗大量的性能,所以要權衡利弊,有所選擇。

    渲染流程的CSS優化

    CSS的渲染是從右到左進行匹配的,我們應該注意:

    • 避免大量使用通配符,可選擇需要用到的元素
    • 關注可以通過繼承實現的屬性,避免重復匹配,重復定義
    • 少用標簽選擇器,例如.header ul li a
    • id和class選擇器不應該被多余的選擇器拖后腿,例如.header#title
    • 減少嵌套,后代選擇器的開銷最高,不要一大串,要將選擇器的深度降到最低,盡可能使用類來關聯每一個標簽元素。

    CSS阻塞

    我們將css放在head標簽里和盡快啟用CDN實現靜態資源加載速度的優化,因為只要CSSOM不OK,那么渲染就不會完成。

    JS阻塞

    JS引擎是獨立于渲染引擎存在的,就是說插在頁面那,就在那執行,瀏覽器遇到script標簽時,它就會停止交于JS引擎渲染,等它渲染完,瀏覽器又交于渲染引擎繼續CSSOM和DOM的構建。

    DOM渲染優化

    也就是說重繪回流問題

    • 回流:前面我們通過構造渲染樹,我們將可見DOM節點以及它對應的樣式結合起來,可是我們還需要計算它們在設備視口(viewport)內的確切位置和大小,這個計算的階段就是回流。
    • 重繪:最終,我們通過構造渲染樹和回流階段,我們知道了哪些節點是可見的,以及可見節點的樣式和具體的幾何信息(位置、大小),那么我們就可以將渲染樹的每個節點都轉換為屏幕上的實際像素,這個階段就叫做重繪節點。

    當頁面布局和幾何信息發生變化的時候,就需要回流。比如以下情況:

    • 添加或刪除可見的DOM元素
    • 元素的位置發生變化
    • 元素的尺寸發生變化(包括外邊距、內邊框、邊框大小、高度和寬度等)
    • 內容發生變化,比如文本變化或圖片被另一個不同尺寸的圖片所替代。
    • 頁面一開始渲染的時候(這肯定避免不了)
    • 瀏覽器的窗口尺寸變化(因為回流是根據視口的大小來計算元素的位置和大小的)

    注意:回流一定會觸發重繪,而重繪不一定會回流,回流比重繪做的事情要多,帶來的開銷也大,在開發中,要從代碼層面出發,盡可能把回流和重繪的次數最小化。

    如何最小化重繪和重排

    • 用 translate 替代 top
    • 用 opacity 替代 visibility
    • 不要一條一條的修改 DOM 的樣式,預先定義好 class,然后修改 DOM 的 className
    • 把 DOM 離線后修改,比如:先把 DOM 給 display: none(有一次 reflow),然后修改100次,然后再顯示出來
    • 不要把 DOM 節點的屬性值放在一個循環里當成循環里的變量
    • 不要使用 table 布局,可能很小的一個改動就會造成整個 table 的重新布局
    • 動畫實現的速度的選擇
    • 對于動畫新建圖層
    • 啟用 GPU 硬件加速

    優化總結

    本文主要介紹的是 代碼層面 的性能優化,經過上面的一系列優化,首頁打開速度有了明顯的提升,雖然都是一些常規方案,但其中可以深挖的知識點并不少

網站首頁   |    關于我們   |    公司新聞   |    產品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有