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,包括但不限于帮助构建 web 原生单页面

  •  
  •   lesismal · 2021-01-10 18:37:09 +08:00 · 3378 次点击
    这是一个创建于 1438 天前的主题,其中的信息可能已经有所发展或是发生改变。

    项目地址

    pm.js

    另外捎带个项目,golang 高性能、功能丰富的网络交互 /RPC 框架 ARPC

    因为本来是想写点前端的项目辅助宣传 ARPC 的,但是迫于前端学不动,并且从理论上讲,react 、vue 那些最终还是原生、虚拟 dom 也不可能比高手写的原生性能好,所以写了 pm.js ,不求为前端社区做出多大贡献,但愿能给道友们带来一些新的思路、简化工程、保住秀发

    一些示例

    主要功能

    1. 发布订阅
    2. 元素与事件订阅
    3. 多页面 /元素显示隐藏互斥关系管理(构建单页面)
    4. 简单的请求、html/js 异步加载封装
    • 源码 200 多行,有需要的请自行压缩,压缩后 2-3k

    pm.js 实现原生单页面的原理

    • 传统 web 前端开发多是通过改变路由切换页面,reload 消耗大、性能差
    • 近几年 react 、vue 的崛起很大程度上提升了性能,主要是单页面、router 之类的,一些原生单页面应用的方案应该也是类似的思路,具体原理是啥没深入研究,只说说 pm.js 的实现方案吧:
    1. html 主页面包含一组空 dom 元素,非默认显示页的 dom 元素设置隐藏( display: none )
    2. 使用 pm.js 根据配置绑定这组 dom 元素的关联关系,按照实际子页面的显示时机比如 $pm.select(dom id),同步或异步加载该 html 子页面作为主页面的 dom 元素内容
    3. 通过 style.display 属性控制不同子页面元素的显示或隐藏,只有当前页面被显示、其他页面被隐藏
    • 特点:
    1. 不需要改变路由,而只是选择当前页面
    2. 可以绑定触摸时间的 src-dst 关系,点击 src 时自动切换页面
    3. 提供释放页面方法,可以在页面隐藏时释放、下次显示时重新加载,业务层可以根据需要自行管理

    一点工程性建议

    1. 鼓励使用有组织有纪律的 id 进行 dom 元素的工程管理
    2. 鼓励使用事件 /发布订阅机制,统一处理 dom 事件、网络消息事件等的分发,页面内容进行事件绑定 /订阅,从而事件触发时的内容自动更新(这本来是个挺简单的事情,但是 react redux 之类的搞得过于复杂、云里雾里,前端阵营老师这么玩、所以才有前端学不动了现象)
    3. 少即是多,鼓励简化工程复杂度
    22 条回复    2021-01-22 15:02:28 +08:00
    lesismal
        1
    lesismal  
    OP
       2021-01-11 08:54:33 +08:00
    周一搬砖日,up up ~
    lesismal
        2
    lesismal  
    OP
       2021-01-11 12:51:19 +08:00
    看来大家都去搞 react 、vue 了,没人关心 native 了 😂
    Kasumi20
        3
    Kasumi20  
       2021-01-11 16:45:09 +08:00
    路由都没有,真·单页面
    lesismal
        4
    lesismal  
    OP
       2021-01-11 17:36:32 +08:00
    @Kasumi20 如果业务层觉得有必要,完全可以自己使用路由。只是使用 pm.js 的方案不需要使用路由,并且通常没有必要,这在 GUI/H5 GAME 领域很常见。
    需求仍然可以按照多个 html 进行工程管理。传统路由方案是为了切换页面,pm.js 的一样能达到而且简单方便、可以得到最佳性能保障,而传统 native 路由切换页面的方案正是常规项目性能的最大瓶颈所在。
    shunia
        5
    shunia  
       2021-01-11 19:07:07 +08:00
    改变路由何来的结论会导致 reload,又何来的消耗大?
    而且也没听说谁开发 SPA 项目遇到了 router 导致的性能问题啊?

    另外和 React 、Vue 对标的说法不叫 native 吧,非要形容应该是原生 Javascript,也就是 Vanilla Javascript ?

    go 多好啊,折腾什么 Javascript
    lesismal
        6
    lesismal  
    OP
       2021-01-11 20:19:41 +08:00
    @shunia 我不知道我理解的路由是否正确,如果说的不准确,多多指正。
    我上面说的是传统方案的路由(不是 react 、vue 的路由)——传统 web 前端方案主流应该是 window.location 吧,然后是 reload,性能差。说的是传统方案这样性能差,好像没说对标 react 、vue 的路由导致性能差。

    如果你理解成对标 react 、vue,那么对标的部分我是指它们的虚拟 dom,因为最终都是操作 native,所以如果 native 实现方案合理,react 、vue 并不会比 native 性能更高。

    “go 多好啊” —— 严重同意,所以我也不是折腾 js 后端,只是捎带一点前端思路
    lesismal
        7
    lesismal  
    OP
       2021-01-11 20:23:35 +08:00
    @shunia redux 这种,核心本质就是事件分发数据驱动,但是它搞得太复杂了。所以前端社区学不动,甚至很多非前端的老司机想搞下前端都忽觉门槛奇高,这于工程性不够友好。

    虚拟 dom 系的新栈最大的好处是强行提高了门槛,强行约束了工程规范,虽然依旧是屎山,但是不是什么样子的小白都能爬上山了,所以现在这些山上的人们,至少做事能力靠谱了很多,而且在这山上再能制作出很漂亮的前端产品,确实是值得肯定的,因为比用 go 写一些基础业务还是要难度大很多的。
    otato
        8
    otato  
       2021-01-12 03:02:35 +08:00
    你这个其实就是个路由嘛,或者说加载器,功能感觉够了,安心当个路由吧。

    每个页面里面的逻辑简单的就写原生,稍微复杂一点的用 vue 完整版(带模板解析器的,直接就可以在页面里写不用 build ),或者其他什么框架,再复杂的还是得上前端那一套。

    虚拟 DOM 的性能,就是在 js 里对比一下,不操作 dom,不占多少时间,最后 diff 算法算出来的实际 DOM 操作,基本就是最优解。现在直接大段 innerHTML 确实性能最好,但是再细的粒度呢,要么使用者手动去操作 dom,要么你实现个中间层,可是,这个中间层,不也就会是个虚拟 DOM 么 23333

    事件系统建议就用在页面间传数据或者跟主程序通讯,发布 /订阅模式适合做底层不适合在业务中全面使用。
    早期有框架使用,比如 riot.js ,我用过一次,初始简单直接,但是一旦事件数量上去甚至开始事件联动之后,混乱程度指数上升。当然我当时确实也挺菜的,不过估计现在写也不会好多少。
    lesismal
        9
    lesismal  
    OP
       2021-01-12 10:01:05 +08:00
    @otato

    “你这个其实就是个路由嘛,或者说加载器,功能感觉够了” —— 定义不一样也不那么重要,但是要实现的功能是类似的,这个方案并不是以 web 为出发点的来做的,而是以 GUI 为出发点捎带着给 web 领域的。浏览器本身是在 GUI 系统之上发展起来的一套复杂姿势,但 GUI 领域比如桌面、游戏引擎,都相对规范得好一些、没有 web 领域这么繁杂松散

    “虚拟 DOM 的性能,就是在 js 里对比一下” —— 这个说法不够详细,不知道兄弟你的意思是对比单个 dom 还是整个 dom 树,我没有读过 react 、vue 的源码、不确定它们的实现方案。如果我自己实现虚拟 dom,我不会去实现管理整个 dom 树所有节点,只会去按照初始化后触发修改才去把相应的 dom 元素加到管理列表,每次触发修改也只对比这个元素自己然后更新

    “”现在直接大段 innerHTML 确实性能最好,但是再细的粒度呢“ —— 这个理解是不准确的,直接大段只是加载子页面时一次性 load,不是每次有 dom 元素变更都需要 reload 大段

    “”要么使用者手动去操作 dom,要么你实现个中间层,可是,这个中间层,不也就会是个虚拟 DOM 么 23333" —— 手动操作 dom 是对的,不需要另外实现个中间层、虚拟 dom 是有些多余的

    ”事件系统建议就用在页面间传数据或者跟主程序通讯,发布 /订阅模式适合做底层不适合在业务中全面使用。
    早期有框架使用“ —— 所以提供了单独 bind dom 元素的只用来更新需要动态变化的 dom 。其他的很多功能比如复杂的 UI 组件,还是交给 UI 框架,pm.js 并不是做全套解决方案,只是提供单页面方案或者工程性的基础
    lesismal
        10
    lesismal  
    OP
       2021-01-12 10:05:35 +08:00
    @otato pm.js 原理和实现都很简单,不是什么高深的玩意。只是我想做些页面,选用一些 UI 框架时看到的一些工程示例,比如 github 上数万 star 的 bootstrap admin 模板项目,dashboard 切换功能标签时是 url 路由到新页面、每次都全部重新加载,性能损失太亏了。
    lesismal
        11
    lesismal  
    OP
       2021-01-12 10:16:04 +08:00
    @otato 我不是 web 前端工程师,也不太了解前端社区特别好的解决方案细节、只是偶尔了解一点。想做一点页面,但是 react 、vue 这些需要更多时间熟悉它们的基础,想直接原生搞,然后原生的框架没有找到我满意的姿势(自己对性能有些强迫症),就搞了 pm.js 这么个,简单归简单,但是工程性在架构分层的不同层里,每一层处理好自己的只能就好,pm.js 是 Page Manager 的意思,如果是我自己用我会理解成 Project Manager,因为在 pm.js 管理页面基础上的工程结构,再加上动态 dom 元素的事件绑定和动态更新,另外找一套漂亮的 UI 框架,基本就足够了(可能还有一些其他细节比如 i18n 国际化之类的不赘述)

    代码层面的工程管理本身并不需要太多东西,只是被有的人有的社区搞得有些过于复杂甚至华而不实,学起来头大用起来繁琐,虽然也是一种工程规范,但本来可以搞得简单些,就像独孤九剑,我不想玩花架子 :joy::joy:
    lesismal
        12
    lesismal  
    OP
       2021-01-12 10:27:48 +08:00
    @otato 所以 react vue 这些没火起来以前的 web 前端薪资水平比后端低很多
    原生方案时代很少有人去做优秀的 web 前端工程的性能提升,多数的原生工程管理集中在目录结构、没有涉及到 dom 渲染的性能层次
    多数的框架也都是 UI 相关框架、主要性能关注也是在 UI 组件本身、也没有染指提升工程整体性能的层次,或者像 jQuery 这种,也提供了很多便利性而并非性能优化
    传统前端不太在意性能,直到虚拟 dom 系出来搅局,原生更加显得被低估,而虚拟 dom 系的这些并没有真正提升 native 本来可以达到的高度,这是件挺可惜的事情——说句不好听的,前端社区里真正懂底层、性能人相对比较少
    shunia
        13
    shunia  
       2021-01-12 10:28:55 +08:00
    首先你这个东西主要针对单页面,那就不要对标需要加载页面的情况。非 SPA 有各种存在的原因,比如说如果要考虑 SEO,多页面就比单页面方便很多。
    其次即便是你所谓的 native,也很早就有使用 history 来进行页内跳转的小型框架了,不是没有,依然是看需求而已。
    再次 redux 所谓的搞得太复杂了前端社区学不动了,真不知道是哪来的自信写出这样的话?不仅 redux 本身并不复杂,而且前端使用 redux 的大有人在,并且的并且也并不是人人都需要用 redux 。

    ‘虽然依旧是屎山’ 你写你的框架,我写的 Javascript 屎山关你屁事?在这强行提高自己自高 go 干嘛呢,当自己是 Linus ?

    你可以不想学 Javascript 世界的新东西,这没问题,但是既不去了解,也不做客观的比较,匪夷所思。
    lesismal
        14
    lesismal  
    OP
       2021-01-12 11:34:17 +08:00
    @shunia

    也很早就有使用 history —— 这个我不懂,但是它是否需要重新渲染页面?如果不需要,那性能没什么损失,还好

    redux 之类的,你觉得简单已经学会,不代表大多数人的感受。我的观点也不能代表所有,但是至少我是这样的感受,并且包括 node 之父自己的一些观点以及 deno 刚出来时候有成都小伙去炸 issue 的时候,或者说现实世界里的前端同事也很多这种感受的。

    ‘虽然依旧是屎山’ 你写你的框架,我写的 Javascript 屎山关你屁事 —— 我说是屎山,这个是否定早期的前端技术栈,并不是否定写前端的人,我原来的描述里也说了,能把前端做好的确实是值得肯定的。也没有强行提高 go

    你可以不想学 Javascript 世界的新东西,这没问题,但是既不去了解,也不做客观的比较,匪夷所思。 —— 我写出来的都是自身感受,如果理解不到位,多指教、交流就可以了

    但是,淡定点,聊个技术,不要逮到个字眼就随便自己臆测出别人存在恶意或者曲解别人的含义,气大伤身
    otato
        15
    otato  
       2021-01-12 12:06:20 +08:00
    提供单页面方案或者工程性的基础,这不跟我一个意思嘛
    接下来不是跟你抬杠,只是有些问题你理解错了
    首先真没 native 这个说法,你可能理解成那些跨平台 APP 方案了,那种方案的性能损耗一般来自框架和平台 API 的通信上,但 r/v 都是 js,跟原生 js 跑在同一个页面里,没那些损耗。
    再就虚拟 DOM,我举个例子吧:
    列表渲染 1234,要更新成 5234,性能最好肯定是直接 1 => 5,不过实际应用中你怎么知道 1 变了呢,要么不管他全量更新,要么自己去 diff 变化,但这增加了心智负担
    虚拟 dom 就能做到,你就 list = 5234,他自动帮你算出来,只要把 1 更新成 5 就行了
    这种简单场景可能全量更新也很快,可万一列表里面是个复杂一些的功能组件呢,有自己的状态和事件绑定,这些都要手动处理,可就保不住头发了
    真的,作为一个摸到一些 jquery 时代尾巴的前端,这些框架其实降低了开发难度的。
    不过发展到现在确实概念多了产生一些壁垒,这里再次建议尝试一下完整版的 vue,直接在页面里写模板,处理事件+双向绑定,什么组件、vuex 、router 通通没有,不用打包编译,引个 vue.js 就行,文档首页就在强调的渐进式框架,就是给你这种场景用的
    lesismal
        16
    lesismal  
    OP
       2021-01-12 12:31:45 +08:00
    @otato

    “提供单页面方案或者工程性的基础,这不跟我一个意思嘛” —— 对的,就是这个意思

    “接下来不是跟你抬杠,只是有些问题你理解错了,首先真没 native 这个说法” —— 我也不确定,不常混前端社区,只是看到有人这么说,以为传统的非 react 、vue 就是 native 呢,多谢指正

    “列表渲染 1234” —— 这个例子其实虚拟 dom 不管是哪种实现,如果是通用的功能肯定做不到最佳,当然我也不是追求完全的性能最佳,通常不影响性能体验的小消耗还是便利性优先就行了,至于复杂 UI 之类的,还是交给 UI 框架自己处理吧,否则搞一整套也是个大工程

    “这里再次建议尝试一下完整版的 vue” —— 我原计划也是,原生然后 react 和 vue 看看,react 看着有点复杂,暂时也打算 vue 一波,另外就是,前端这几年变化太快了,之前也偶尔看过一波,结果 vue 又说 3.0 了,还不知道 node 爹的 deno 未来会不会带起来节奏、但是目测有点难了,node 已经形成的庞大社区有点船大难调头了
    lesismal
        17
    lesismal  
    OP
       2021-01-12 13:37:31 +08:00
    @otato 搜了下 native 相关的,似乎前端社区原生 js 可以叫 native,比如:而 react native 只是 react 移动端的、这个只是 react 内部的区分
    lesismal
        18
    lesismal  
    OP
       2021-01-12 13:41:44 +08:00
    @otato V 站不能编辑,哎,上面一条编辑中、手抖就发了

    搜了下 native 相关的,似乎前端社区原生 js 可以叫 native,比如:
    https://stackoverflow.com/questions/41948057/native-javascript-vs-jquery-real-world-performance-vs-theoretical-benchmarks/41948449

    而 native 对于 react 只是 react 的移动端绑定原生方案,这里的 native 适用范围是在 react 而不是指整个前端 js

    各种技术都不简单,不同的社区、框架不同的命名、叫法太多了 😂
    zlu1123
        19
    zlu1123  
       2021-01-12 15:20:23 +08:00
    先无脑给个 star
    lesismal
        20
    lesismal  
    OP
       2021-01-12 15:27:38 +08:00
    @zlu1123 感谢 star,我还是前端新人,努力学习改进 ^_^
    lesismal
        21
    lesismal  
    OP
       2021-01-22 14:43:48 +08:00
    @shunia 感谢之前指出的相关知识点,最近研究了下 history 和 hash 路由,选择了对 hash 路由做点支持、根据路由切换内容,hash 路由确实不算复杂,但是内容管理本身还是需要原来的部分

    随便找了个 admin 的模板项目,用 pm.js 、hash 路由切换内容的方式改造了下,去掉了多个页面大量的重复内容、去掉不必要的重复加载、重复下载之类的,切换内容更加顺滑、性能要好太多。我对前端不熟悉,各位交流中指出的问题能方便我更快去找到相关知识点、改进计划。

    如有兴趣欢迎多来指点、给些批评建议:

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

    :smile::smile:
    lesismal
        22
    lesismal  
    OP
       2021-01-22 15:02:28 +08:00
    @otato 对 hash 路由切换页面内容做了支持,fork 了个 admin 模板项目,用 pm.js 改造了下,去掉了多个页面大量的重复内容、避免不必要的重复加载、重复下载之类的,对比 fork 原作,切换内容顺滑、性能基本能达到极致了

    欢迎来指点、给些批评建议( v 站不让每个回复都带外链,只能加另外一个帖子的链了):

    https://www.v2ex.com/t/747412#reply0
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2691 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 00:21 · PVG 08:21 · LAX 16:21 · JFK 19:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.