V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yesvods
V2EX  ›  前端开发

极致 PCWeb 性能 —— 静态化&工程化 JSONP

  •  
  •   yesvods ·
    yesvods · 2017-06-24 22:20:59 +08:00 · 2467 次点击
    这是一个创建于 2709 天前的主题,其中的信息可能已经有所发展或是发生改变。

    作者:Jogis

    原文链接: https://github.com/yesvods/Blog/issues/13

    转载请注明原文链接以及作者信息

    在大家的认知里,JSONP,往往是另外一种异步请求的方式,其主要优点是支持跨域数据请求。因此,JSONP 往往是将一个 Script 节点动态插入 document,随后浏览器会自动发起一个远程请求。

    除了上述单一用法外,在 PCWeb,JSONP 具有非常巨大的性能&工程化价值。

    1.异步 JSONP

    通过 [图说舌尖上的脚本] 与 [同步 vs 异步加载] 了解到,PCWeb 受限于插件环境,异步机制变得非常不吃香。异步发起的请求,无论是 JSONP 等资源加载,抑或 XHR ( fetch ),都会被标记为低优先级。

    • 同步插件脚本加载完才能发起请求
    • 在主进程的编译与执行前,会被插件脚本抢占。

    我们来看一下,发起 6 个异步 JSONP 是怎样的情况:

    <script>
    function appendScript(src){
     var s = document.createElement('script')
     s.src = src
     document.body.appendChild(s)
    }
    for(let i=0;i<6;i++){
     appendScript(`./react.js?v=${i}`)
    }
    </script>
    

    结果跟之前分析的异步请求别无二致,异步 JSONP 默默低下了头。

    2.同步 JSONP —— 将页面加载性能发挥极致

    2-1. 现实中的场景

    举个栗子,在实际 PC 场景,无论采用的是 React Or Vue Or what ever. 我们都需要在渲染前加载一堆组件,数据+模板(JSX etc.)+组件方式,来实现渲染。我们在渲染页面前就需要加载一堆资源,有时候甚至可以达到 2M 之大!

    2-2. 性能分析

    这块大资源并没有错(有时候利用一块大资源,比起每次加载不一样非缓存资源性能还高),但是在浏览器加载这块大头时候,脚本的解析、编译、执行,也随着体积增长(特别是执行耗时)。当然,这也有一些办法可以减轻这些负担(未完,待续..)。然而,我们可以利用上面介绍到的同步 JSONP 优雅地减少页面加载时间!我们先来回顾一下部分原理:

    因为主线程被阻碍了,后面的解析工作没有办法继续往下进行,
    当遇到这种情况,WebKit 会启动另外一个线程去遍历后面的 HTML,
    收集需要的资源 URL,然后发送请求,这样就可以避免阻塞。 
    	———— 《 WebKit 技术内幕》
    

    2-3. 优雅技术方案

    我们把资源都看成一个大体积 Bundle,在 HTML 解析到这个脚本时,由于无需下载(memory cached Or disk cached),接下来就是漫长的解析、编译、执行。但是,我们可不能让浏览器闲着,通过同步 JSONP,在 Bundle 后面声明一堆以后渲染要用的页面数据。这样,浏览器主进程漫长的阻塞执行过程中,相关的数据已经被网络模块准备就绪,由于模块数据相对体积小,因此没有解析 /编译 /执行成本。

    <script src="BigBundle.js"></script>
    <script src="parallelData1.js"></script>
    <script src="parallelData2.js"></script>
    <script src="parallelData3.js"></script>
    <script src="parallelData4.js"></script>
    <script src="parallelData5.js"></script>
    <script src="parallelData6.js"></script>
    

    我们一直提到的是,在 PCWeb 页面初始化场景,异步加载都会面临性能问题。而上述的方案通过所有资源同步的方式实现,用最高优先级来渲染初始页。

    2-3. 真实的故事

    在鄙人的某些业务场景下,真实用到同步加载 Bundle,异步获取资源,首屏渲染时间惨不忍睹。仅仅通过资源 JSONP 同步化,还没做其他优化😕,首屏时间直接从 2.1s,下降至 1.4s😱。

    9 条回复    2017-06-25 14:29:45 +08:00
    MinonHeart
        1
    MinonHeart  
       2017-06-25 00:09:57 +08:00 via Android
    JSONP 还有同步一说?喵喵喵???
    yesvods
        2
    yesvods  
    OP
       2017-06-25 00:56:16 +08:00
    @MinonHeart 可以先屡清楚 JSONP 是什么意思
    jsq2627
        3
    jsq2627  
       2017-06-25 02:41:37 +08:00 via iPhone
    不就是预加载数据嘛,做到极致就是服务端渲染了。
    同步 JSONP 是楼主自创的概念吗?
    zhoufenfens
        4
    zhoufenfens  
       2017-06-25 02:57:07 +08:00 via Android
    这也不能叫同步吧,
    jin5354
        5
    jin5354  
       2017-06-25 07:10:14 +08:00
    这是预加载啊。。另外在工程中怎么把 jsonp 都抽出来预先声明也是问题
    我的项目里都去 jsonp 用 CORS 了
    yesvods
        6
    yesvods  
    OP
       2017-06-25 10:45:26 +08:00
    @jsq2627 服务端渲染,考虑一下,如果数据预拉取需要 1s,这段时间用户在浏览器是一块白屏,相反如果用这种方式,大多数样式框架都已经出来了,反而很友好。
    yesvods
        7
    yesvods  
    OP
       2017-06-25 10:48:37 +08:00
    @jin5354 这个涉及到工程化改造,JSONP 化加一个中间件的事情,预读取数据可以用另外一种形式声明,在服务端渲染时候同步输出到 HTML
    jin5354
        8
    jin5354  
       2017-06-25 13:13:26 +08:00
    @yesvods 服务端渲染这个还比较有用,客户端渲染没办法在 bundle 执行完毕前抽出 jsonp
    yesvods
        9
    yesvods  
    OP
       2017-06-25 14:29:45 +08:00
    @jin5354 这篇文章介绍的就是客户端渲染场景做的优化,怎么抽出来,就是工程化做的事情了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2783 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 08:31 · PVG 16:31 · LAX 00:31 · JFK 03:31
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.