尝试用 pm.js spa 方案改造了一个原生 js 的 admin 模板项目,性能大幅提升 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
lesismal
V2EX    Javascript

尝试用 pm.js spa 方案改造了一个原生 js 的 admin 模板项目,性能大幅提升

  •  
  •   lesismal 2021-01-22 14:55:04 +08:00 3172 次点击
    这是一个创建于 1799 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前阵子发布过 pm.js ,原帖在这里:

    发布 pm.js ,包括但不限于帮助构建 web 原生单页面

    非专业前端,用词未必准确,脸皮防御值高,欢迎来喷。。。

    最近随便 fork 了个 admin 的模板项目,用 pm.js 改造了下,去掉了多个页面大量的重复内容、避免不必要的重复加载、重复下载之类的,对比 fork 原作,切换内容顺滑、性能要好太多,不谦虚地说,就是性能基本能达到极致了

    我对前端不算熟悉,所以暂时主要研究研究框架相关

    有兴趣的朋友欢迎多来指点、给些批评建议(性能提升跟 fork 原作对比就可以了):

    https://github.com/3rdrepo/adminkit

    10 条回复    2021-01-25 15:36:15 +08:00
    bmwh123
        1
    bmwh123  
       2021-01-22 17:28:40 +08:00
    有一个问题就是设置成 display none 的页面也是会加载的,那首屏的加载时间随着项目膨胀也会变长很多,这个怎么解决的呀
    lesismal
        2
    lesismal  
    OP
       2021-01-22 18:13:28 +08:00
    @bmwh123 有个 lazy 选项,lazy: true 的子页面是等到需要展示的时候才进行异步加载的,比如:

    https://github.com/3rdrepo/adminkit/blob/dev/static/js/init.js#L18

    每个页面可以配置:

    {
    src: "pages-profile.src", // 这 id 的元素 onclick 时会切换内容到 dst
    dst: "pages-profile.html",
    url: "page/pages-profile.html",
    lazy: true, //如果 url 不为空,lazy 为 true 则等到首次显示 dst 内容时加载 url 对应的子页面
    init: function() {...}, //首次显示时调用
    onshow: function(){...}, //被显示时调用
    onhide: function(){...}, //被隐藏时调用
    }
    lesismal
        3
    lesismal  
    OP
       2021-01-22 18:17:22 +08:00
    @bmwh123 还提供了$pm.release(page),可以用于释放单个 page 的内容,如果应用层子页面内容太多想减少总资源占用压力,可以根据自己的需要、在 onhide(page) 中选择是否对该子页面内容释放,就是对该 dom 元素的 innerHTML 设置为""。
    lesismal
        4
    lesismal  
    OP
       2021-01-22 21:04:22 +08:00
    @bmwh123 抱歉才看懂问题,前面的回答默认以为大家知道实际的机制了呢。。。

    实际上单个大页面分为主页面和子页面,主页面里大概是这样子的:

    <div class="main">
    <div id="nav"></div>

    <div id="dashboard.html"></div>
    <div id="charts-chartjs.html"></div>
    <div id="forms-basic-inputs.html"></div>
    <div id="forms-layouts.html"></div>
    <div id="icons-feather.html"></div>
    <div id="maps-google.html"></div>
    <div id="pages-blank.html"></div>
    <div id="pages-invoice.html"></div>
    <div id="pages-profile.html"></div>
    <div id="pages-settings.html"></div>
    <div id="pages-sign-in.html"></div>
    <div id="pages-sign-up.html"></div>
    <div id="tables-bootstrap.html"></div>
    <div id="ui-alerts.html"></div>
    <div id="ui-buttons.html"></div>
    <div id="ui-cards.html"></div>
    <div id="ui-general.html"></div>
    <div id="ui-grid.html"></div>
    <div id="ui-modals.html"></div>
    <div id="ui-typography.html"></div>

    <div id="footer"></div>
    </div>

    每个子 div 的 id 对应一个子页面,然后才是上面 lazy 相关的回答,如果 lazy 默认是不加载的、而等用户首次点击触发 $pm.select(...) 或者代码 $pm.select(...) 时才去加载的,并不是进到主页默认就把所有加载进来
    lesismal
        5
    lesismal  
    OP
       2021-01-22 21:05:45 +08:00
    not lazy 的是进来就加载的,都可配,业务层自由管理
    alan0liang
        6
    alan0liang  
       2021-01-23 11:43:13 +08:00 via Android
    原作问题真的是太大了……基本怎么优化都能好很多
    一个 1.6M 的 app.js (优化:split chunks )被所有页面使用(优化:分 entrypoint 按需加载),还没有缓存(优化:immutable + 缓存),还没有 CDN (优化:静态资源单独走 CDN ),这能不慢吗
    lesismal
        7
    lesismal  
    OP
       2021-01-23 12:34:03 +08:00
    @alan0liang 是啊,我找了好几个 bootstrap admin template,都差不多的情况。可能这些主要是为了展示 template 功能、没做优化,但是既然是作为 template,别人拿来用也是希望快速实现功能,所以性能问题还是太不友好了。
    还有很大程度上其实应该是使用传统原生 js 方式的的老技术、工程体系的锅,react vue 崛起之前的前端社区的大部分人缺少工程思维,react vue 崛起后框架强行工程优化了
    bmwh123
        8
    bmwh123  
       2021-01-25 09:28:09 +08:00
    @lesismal 听起来感觉蛮不错的 项目有文档嘛 我再研究研究,要是可以用到公司的老项目上就好了
    lesismal
        9
    lesismal  
    OP
       2021-01-25 15:34:52 +08:00
    @bmwh123 其实就是把老方案的内容摘出来放到单独的 html 子页面,index.html 里放上对应的 dom 元素,用 pm.bindPages 绑定这些 dom 元素的 id 和对应的子页面 url,可以手动 $pm.select 切换页面 也可以带上 src 配置项在对应的 dom onclick 时自动切换内容,或者配置的 dst 值就用 router,然后 $pm.listenRouter 用路由的方式自动切换,比如:

    <div id="menu" class="side_bar">
    <div style="height: 2px;">&nbsp;</div>
    <button class="button">
    <a href="#page_1" class="button">Page 1<br>Click Me</a>
    </button>
    <div style="height: 2px;">&nbsp;</div>
    <button class="button">
    <a href="#page_2">Page 2<br>Click Me</a>
    </button>
    </div>

    dom 树上两个 <a> 分别路由到:
    href="#page_1"
    href="#page_2"

    // 页面配置 && 绑定
    let pages = [
    {
    dst: "page_1",
    url: "page/page_1.html",
    },
    {
    dst: "page_2",
    url: "page/page_2.html",

    // lazy 为 true 时则第一次显示时才进行加载,否则进入页面就开始加载
    lazy: true,
    },
    ];
    $pm.bindPages(pages);

    // 显示 page_1
    $pm.select("page_1");

    // 监听路由变化、自动切换页面,比如路由切换到 #page_2 时,相当于执行 $pm.select("page_2")
    $pm.listenRouter();
    lesismal
        10
    lesismal  
    OP
       2021-01-25 15:36:15 +08:00
    完整的例子可以看这里:
    https://github.com/lesismal/pm/tree/master/examples/bind_src_dst

    还有个项目是 fork 了个别人的 admin template,用 pm.js 改造了下,可以直接对比 fork 的原作,性能提升太明显了。。
    https://github.com/3rdrepo/adminkit
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2474 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 33ms UTC 15:25 PVG 23:25 LAX 07:25 JFK 10:25
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86