京东资深前端架构师分享前端工程化在电商首页中的实践

大家好,我是京东用户体验设计部前端架构团队的刘威,网上ID是putaoshu,非常高兴 “ITA1024团队”的邀请,有这样的一个机会与大家分享下我们团队关于2015年京东PC新首页的一些前端开发实践,希望通过今天的讲解能为大家以后在大型前端项目开发和改版时提供一个思路和参考。

 

今天我的讲解主要分为两部分,具体如下:

京东首页前端架构设计与实现

  • 面临挑战
  • 前端页面静态化
  • 前端页面整体架构
  • 前端页面加载策略
  • 前端基础架构
  • 前端工具和系统
  • 前端灾备策略
  • 前端性能优化

前端工程化在电商首页的实践

  • 命令行工具
  • 前端模块
  • 前端组件
  • 前端开发流程
  • 前端文档
  • 实际应用

 

京东首页前端架构设计与实现

面临挑战

  • 页面DOM元素剧增:单个楼层Tab标签由5个到9个
  • 页面整体高度翻倍:算上头尾,共计14个楼层,高度也由4820px到9862px
  • 页面图片量增加:80%的位置变为图片展示
  • 首屏加载时间要有保证:加载时间相比原来不能增加
  • 首页独特的影响力:页面不能空白,不能有报错
  • 大流量高并发,对稳定性要求极高
  • 对接业务方很多,临时需求、紧急需求较多

前端页面静态化
众所周知,一般网站首页栏目会有很多,不同栏目的数据库查询方式也不同,而首页流量巨大,如果按照一般的动态网站每次用户来时查询后台数据库取数据的话,开销巨大,从而导致首页访问速度降低,于是要考虑做静态化,我们具体的架构如下:

 

接入层:CDN—>HAProxy—>nginx

应用层:PHP Redis

存储层:Mysql

首先,用户访问首页实际是请求CDN上拼接好的静态页面,往下会到达Nginx动态缓存,然后到达Nginx,Nginx再把请求转发给PHP进行处理,并通过HTTP头来精确控制缓存;接着到了PHP应用层,使用了Redis作为缓存,并用MySQL存储数据;定时2分钟循环任务生成静态文件,从源服务器同布分发至各地CDN结点。这样用户访问时,会访问到离当前用户最近CDN结点机器上拼装好的静态文件。

前端页面整体架构

  • JS部分

首页页面依赖的JS库为jQuery V1.6.4版本,前期调研评估后采用这个比较低的版本,是因为首页改版上线后,头尾组件以及一大部分公共组件要推至全站使用,即还要平滑升级上千个一二级页面站点的公共头尾,而旧页面引用了非常旧的jQery版本,要想平滑升级综合评估后,1.6.4这个版本最合适;另外jQuery我们根据整体业务进行特殊修正,就比如jsonp回调函数名称后端规范对长度有要求,我们就对长度进行修正等等。

第二层是JDF公共组件,包括UI组件、Unit业务组件、Widget模块,这些组件包括event,localStorage,焦点图,动画,地区选择,对话框,下拉菜单,懒惰加载,suggestion,login,search,category,cookie等常见交互组件和业务组件;同时也有当前业务级需要的公共组件,比如楼层懒加载组件,楼层切换电梯组件等。

第三层是页面脚本,比如今日推荐楼层,猜你喜欢楼层,广告楼层,天天低价楼层等等。

  • CSS部分

改版前的公共样式base.css耦合不少公共组件样式,现在采用很轻的样式重置ui-base.css,公共组件单独按需调用自身样式,彻底解耦。另外首页所有楼层依赖的样式文件是放在首屏加载,而不是请求当前楼层时异步加载,主要为了保证楼层的高可用性和预加载,另外单一个楼层文件非常小,每次到达时候异步加载并不如放在首屏,所有楼层样式文件combo成一个文件请求加载合算。

前端页面加载策略

常见的前端页面加载策略一般为:后端从数据库读取出数据,拼装好必要的页面元素,图片做lazyload(懒加载),用户通过浏览器加载页面上的所有HTML元素。

基于首屏加载时间最短的原则,我们的页面加载采用:楼层异步加载和本地缓存方式,具体如下:

  •  把页面按楼层进行拆分,把首屏做为页面框架主体,每个楼层的数据,单独做成数据接口,异步加载,页面仅保留一个楼层一个DIV标签,比如如下服饰楼层:

  • 给每个楼层设置默认高度,到达这个区域时请求当前楼层数据文件,同时对楼层数据文件进行md5(即data-time),并把楼层请求后的数据文件和其data-time localStorage至本地,如果页面上的楼层data-time和本地localStorage中的data-time值一样,数据直接取localStorage,如果不一致,重新ajax请求数据,请求后同时会localStorage数据至本地;
  • 第一次ajax请求数据时,会延时5秒,查看请求是否成功,如果成功则退出,如果失败:首先会取上次localStorage数据做垫底数据,但浏览器如果不支持localStorage, 基于高可用性原则考虑会进行第二次ajax请求数据,如果第二请求成功则正常渲染和localStorage楼层,如果第二次请求失败,此时极大可能说明网络存在异常,这时为了保持良好的用户体验,不能留有空白,直接隐藏当前楼层。
  • 其中用户到达当前楼层时,请求楼层数据(包括楼层的html结构和当前楼层的脚本),渲染数据到楼层元素中,同时初始化楼层脚本。另外楼层有提前预加载逻辑,即用户在第一二楼层时,提前加载好第三四五楼层的数据,到达楼层即显示当前楼层数据。

  • 楼层异步加载和本地缓存方式的好处:页面大约共有3288个元素,首屏大约仅900左右,楼层数据lazyload,只渲染首屏元素,大大降低首屏页面内容大小,极大的缩短页面首屏加载完成时间,当时测算首屏约1.6s即加载完,时间比旧版和竞品缩短很多。

  • 数据接口优先请求走本地localStorage,减少后台服务器压力,节约成本。请求数据时延时查看成功与否,同时二次请求保证高可用性。楼层之间数据和脚本完全解耦,有利于后期维护,可随意定时上线和下线运营楼层。

前端基础架构

如下图:

前端工具和系统

主要是以JDF命令行工具为核心进行开发,工具和系统的具体使用步骤如下:

  • 在代码共享平台新建项目工程
  • 使用JDFinit进行项目构建,生成标准化的文件目录和工程文件
  • 使用JDFbuild进行模块编译
  • 使用JDFoutput进行输出
  • 联调时使用JDF upload把编译好的静态文件上传至测试服务器
  • 在页面元素上增加前端统计埋点,检测元素的点击量
  • 联系后端把项目中页面头部和尾部代码放在头尾系统里,以备后续头尾业务变更
  • 上线。上线前通过git提交代码至代码库,上线时在Jone统一工作平台使用线上JDF进行打包;通过Deploy系统把静态文件发布至CDN; 上线后清除静态文件CDN缓存,同时检查线上是否正常;上线后在听云上监控页面性能,定期生成性能报表邮件。

前端灾备策略

灾备是为了保持线上业务在极端很差网络环境下的高可用性,具体做法如下:

  • 本地缓存:异步接口数据优先使用本地localStorage中的缓存数据
  • 二次请求:接口数据本地无localStorage缓存数据,重新再次发出ajax请求
  • 双层接口:部分接口和域名会上线至CDN,业务调用时优先使用CDN接口,如果一定时间内未请求到数据,会用源站接口再次请求
  • 垫底数据:源站接口万一无法访问,使用预设好的垫底备份数据
  • 接口下线:必要时候,下线非核心业务接口和非核心功能

前端性能优化

好的页面性能可以提高页面加载速度,从而增加用户体验,主要如下:

  • 尽可能减少首屏元素数量:用异步加载和本地缓存加载数据
  • CDN加载慢时候,减少页面空白概率:页面CSS样式文件内联在页面上
  • 减少页面请求数量:CSS/JS combo,CSS sprite
  • 减少静态文件体积:CSS/JS/Images压缩
  • DNS预解析:头部增加比如<linkrel="dns-prefetch" href="//d.jd.com"/>
  • 减小Cookie体积等等

前端工程化在电商首页的实践

JDF京东前端开发集成解决方案,核心就是解决前端工程化的问题,包括命令行工具、前端模块、前端开发流程、前端组件、前端文档。

Github地址:https://github.com/putaoshu/jdf/

命令行工具

JDF命令工具基于nodejs,介绍如下:

  • 跨平台

        完美支持windows、mac、linux三大系统

  • 项目构建

        生成标准化的项目文件夹

        支持本地,联调,线上三种开发流程

        每个项目都拥有一个单独的配置文件,按选项统一编译

  • 模块开发

        可快速方便的对模块进行创建,引用,预览,安装和发布

        通过积累,可形成完全符合自己业务的模块云服务

  • 模块编译

        支持模块编译,内置模块编译引挚

        支持将vm和smarty模版编译为html

        支持将sass和less编译为css

        支持ES6

  • 项目优化

        自动将页面中的js、css引用转换成combo请求格式

        自动压缩优化js、css、png文件

  • 项目输出

        默认给所有静态资源添加CDN域名前缀或后缀戳

        支持cmd规范,自动提取文件id和dependencies,压缩时保留require关键字

        支持png图片压缩插件,将png24压缩为png8

        自动生成css雪碧图,并更新background-position属性值

        可将小图片一键生成base64编码

        文件编码统一化,即无论当前文件格式是gbk,gb2312,utf8,utf8-bom,统一输出utf8

  • 项目联调

        一键上传文件到测试服务器,方便其他同学开发预览

  • 本地服务

        支持开启本地服务器,方便调试

        支持本地静态文件预览,内置本地开发调试服务器,以及当前目录浏览

        支持实时监听文件,文件被修改时会自动编译成css,并刷新浏览器

        实时在控制台输出错误信息,方便定位代码错误

  • 辅助工具

        支持html/js/css文件格式化

        支持html/js/css代码压缩

        支持html/js/css文件lint,代码质量检查

        支持chrome浏览器的LiveReload插件

前端模块定义

前端模块即widget:包括配置文件、数据源文件、模版文件、样式文件、JS文件、图片文件,如下ui-product-list为一个widget: 

  • ui-product-list[文件夹]
  • component.json[配置文件]
  • ui-product-list.json[数据源文件]
  • ui-product-list.vm[模板文件或者.smarty文件]
  • ui-product-list.scss[scss文件]
  • ui-product-list.js[js文件]
  • images[图片文件]

 

页面中引用widget用如下代码片断


很明显html不支持{%%}语法,此时会用到jdf的编译命令"jdf  build",核心是把ui-product-list.json中的json数据打到ui-product-list.vm模板上,最后输出静态html片断;同时.scss编译成.css,并且在header头增加样式引用:

页面尾部增加js引用:


输出的时候使用jdf output会把多个wiget中js/css引用变成combo的形式如:


这样就算页面引用N多个模块,也只会发出一个请求

前端模块使用方法

  • 模块安装:(jdf widget -install xxx ) 解决可复用的问题,不用每次都新建,可以先在模块云上查找合适的模块,然后下载至当前项目
  • 模块新建:(jdf widget -create xxx ) 在本地新建一个模块
  • 发布模块:(jdf widget -publish xxx ) 解决了共享和沉淀的问题,项目结项,可以把可复用或者修改后的模块提交至模块云,审核通过就会发布至模块云上
  • 模块预览:(jdf widget -preview xxx ) 用于调试单个模块,同时解决了团队协作问题,项目分成多个独立模块,各负其责
  • 模块列表:(jdf widget -list) 展示模块云上所有模块的列表

搭建成本非常低,只需配置好一台FTP服务器,通过FTP服务器储存,下载,以及分配相关用户权限,版本管理依赖于widget中的componet.json中的version,使用方便,可以使用jdf命令行工具进行发布,下载

前端组件

前端组件主要由UI交互组件和Unit业务组件构成,经过积累,已有以下部分公共组件可供全站使用,如下:

前端开发流程

  • 使用JDFinit进行项目构建,生成标准化的文件目录和工程
  • 引用JDFwidget -install模块云中可以直接使用的已有模块,同时对页面按业务进行拆分,一个同学负责一个或者多个模块,独立开发和调试
  • 使用JDFbuild进行模块编译
  • 使用JDFoutput进行输出
  • 联调时使用JDF upload把编译好的静态文件上传至测试服务器
  • 上线前通过git提交代码至代码库,上线时使用线上JDF进行打包

前端文档

  • 前端文档-规范


文档请参考: https://github.com/putaoshu/jdf/tree/master/doc

  • 前端文档-组件API

生成工具请参考: https://github.com/putaoshu/jdd

  • 前端文档-命令行工具

文档请参考: https://github.com/putaoshu/jdf/tree/master/doc

实际应用

本地新建项目,调用线上模块云相关widget,本地使用JDF工具进行编译,联调,输出,上线时使用线上JDF进行打包,发布至CDN,最后清静态文件缓存。

 

这就是我今天分享的内容,看大家有什么问题请提出,谢谢大家!

 

分享问答

问:公共模块云是自己搭建的,还是基于私有的npm仓库?

刘威:自己搭建的,只需在linux上配置好一台FTP服务器,通过FTP服务器储存,下载,以及分配相关用户权限;有好的模块可以发布,开发项目时候看到已有模块可以下载到当前项目中;版本管理依赖于widget中的componet.json中的version;使用方便,可以使用jdf命令行工具进行发布,下载

 

问:很多这种样式class=“xxx|yyy|zzz” ,是什么意思啊?

刘威:你说的应该是clstag,这是前端埋点统计用的,就是记录某个链接或者某个区域点击的次数,xxx是页面,yyy为楼层,zzz为某个元素,是当前站唯一的标识

 

问:jdf用什么语言写的?go?python?

刘威:Nodejs

 

问:刚才提到的“上线后清理本地缓存”是什么意思,是指服务器的cache么?那么用户本地的资源文件缓存是如何处理的?

刘威:是指清CDN上静态文件的缓存,我们某个项目中静态资源会有统一前缀,比如product/home/1.0.0/a.js,如果项目有更新会发product/home/1.0.1,大型项目会变更大的版本号product/home/2.0.0这样,这样到用户那里都是全新的文件。

 

问:关于cdn缓存,假如有文件更新你们是怎么处理?时间截、md5?

刘威:一般是给静态资源前面加统一的版本号来实现,如果特别小的变动,不想变更文件url,可以在文件上线后,通过CDN后台,手动清当前文件的CDN缓存。

 

问:你们的图片压缩是如何实现的,应用那些组件?

刘威:我们自己根据不同操作系统进行了封装,可以下载https://www.npmjs.com/package/jdf-png-native查看

 

问:模块的依赖解析也是在jdf构建时处理的么?比如a依赖b,b依赖c,在使用a时,是不是会把a b c三个js都加到尾部?

刘威:模块中的js依赖我们基于CMD规范,jdf工具会自动提取文件id和dependencies,压缩时保留require关键字,另外某个项目一般建议有一个统一的入口文件,比如init.js,如果init.js有依赖的通过seajs的combo插件完成全并依赖加载。

 

问:刚才资源文件是用版本号来区分,那么如果多出引用更新后是否需要多处修改版本号?

刘威:我们项目一般会把页面的公共头尾接入公共头尾系统,就是头部的静态html片断以及js/css引用,而项目会对应头尾部系统中某一个编号的头尾,前端静态资源上线后,只需要修改一处,然后系统就会推送到业务线中。

 

问:DNS预解析在不同浏览器的兼容性如何?会不会影响当前页面的性能?确实我们也有一些页面做了上十个DNS预解析,甚至一些暂时用不到的。

刘威:DNS预解析在不同浏览器的兼容性:Chrome: 全部 IE: 9+ Firefox: 3+  Safari 5+ ,可以说大部分高级浏览器都支持的;如果业务依赖的域名很多,建议增加上DNS预解析。

 

问:前后分离的情况下,SEO方面,怎么处理会比较好?

刘威:前后端分离对SEO没有什么大的关系吧,我的建议是最好前端把后端模板层接过来,比如php的smarty,java的vm,由前端来写模板,另外而jdf工具支持.smarty,.vm模板渲染,可以看一下;SPA页面的SEO我还没好的建议

 

问:jdf应该与glup,grunt,fis等类似的构建工具吧,jdf有什么特点?

刘威:jdf比较轻便,另外jdf依赖的npm插件一般经过会我们精心筛选,也有部分第二次封装,不像grunt的插件质量参差不齐;fis相对jdf比较重,fis基于java,php,node都有一套独立的解决方案,而jdf只需要nodejs下即可支持.smarty,.vm模板渲染和解析

 

问:关于页面静态化,有几个问题,1.“并通过HTTP头来精确控制缓存”,这个精确控制指的是什么?2.我是不是可以这么理解,用户请求先访问CDN,如果CDN有数据直接返回,没有数据回源到后端服务器,此时的逻辑是分级缓存策略,减少对服务端上游接口的压力,“定时2分钟循环任务生成静态文件” 这个任务是单独部署一台服务器,只从上游接口拼装数据生成静态html,然后推送同步到CDN节点? 3.静态html从源服务器同步到不同的CDN节点这个是怎么实现的? 4.如果个性化的数据比如根据用户维度下发不同的定向数据,或者是有秒杀楼层等时效性很强的楼层,这个静态化就没有意义了吧?

刘威:1.通过Cache-Control控制,每两分钟更新一次 2.对的 3.生成好静态文件碎片,通过nginx定时任务,从源服务器同步至CDN 4.对的,个性化推荐是通过ajax异步加载数据,每次都不一样。

 

问:如果是统一头尾更新版本号那么是针对各个资源更新还是所有资源?如果是各个资源岂不是要维护很多版本?如何自动化?如果是所有资源用户的缓存岂不是浪费了?

刘威: 恩,jdf工具可以支持所有静态资源加统一前缀版本号,另外我们有线上jdf环境,只需要在本地版本库里更新一下版本号,上线会系统自动处理,再然后这些静态资源上线后通过头尾系统手动更新版本号;当然最理想的方式是前端全部接入模板层,这样头部文件的版本号可以用全部jdf工具来自动更新了,但电商网站的后端系统复杂性暂时选择了半手动的方式,只有部分业务线进行了实现.

 

问:京东是如何处理线下测试smarty模版的?是前端直接在php环境下开发吗 ?

刘威:jdf工具支持.smarty解析,只要nodejs就ok,前端在本地修改测试后,可以一键发送至联调机器

时间: 2024-09-11 18:45:24

京东资深前端架构师分享前端工程化在电商首页中的实践的相关文章

数据-像京东淘宝等电商平台中的公告管理是如何设计的

问题描述 像京东淘宝等电商平台中的公告管理是如何设计的 公告管理的页面中,如果使用的是静态页面,需要用什么控件显示数据,以及显示哪些方面的数据 解决方案 可以用script加载动态页输出js脚本,js脚本document.write输出你的公告内容,也可以用ajax动态加载数据 <script src="你的动态页地址"></script> 解决方案二: 一般公告 都是静态文件, 在html 页面中 include 一个html 文件, 这个文件 是由另一个 c

马云:分享对跨境电商发展认识,呼吁为东盟中小企业减免关税

9月17日电 16日下午,首届中国-东盟电子商务峰会在南宁举行,跨境电子商务成会议焦点议题.阿里巴巴集团董事局主席马云身在国外未能亲自参会,他通过录制视频现场播放的形式分享对跨境电商发展的认识,呼吁为中国东盟中小企业跨境贸易减免关税. 阿里巴巴集团董事局主席马云 马云说,上世纪商业模式讲究大规模,企业拼的是成本.资源.劳动力;进入21世纪以后世界经济将会走向小而美,今后企业拼的不是价格是价值,拼的不是规模是特色. 中小企业在这方面大有可为.马云提出,应该把东盟作为一个经济体来考虑,各国政府应该大

联想高级架构师分享:架构之道-规划、简化和演化

架构这个概念,和计算机科学(包括近几年才成为一级学科的软件工程)的其他术语类似,都是从传统学科借用来的.这是因为计算机科学太年轻.发展太快,来不及形成自己特有的术语和名词.因此,在学习和思考方法上,常常推荐类比法,尝试用一些耳熟能详的事物去理解和解释计算机科学领域的概念,以求"老妪能懂"的效果. 这里介绍的一些内容,大多是个人在学习和实践过程中的一些思考和体会,以及平时的一些学习笔记整理而成,还很不成体系,还有很多需要继续推敲的地方.我会在未来的工作实践中更加深入思考,广泛参考领域内的

首席架构师揭秘蚂蚁金服互联网IT运维体系实践

◆ ◆ ◆ 导 读 本文来自蚂蚁金服首席技术架构师,基础技术部负责人胡喜.从2010年支撑双十一最高交易峰值2万笔/分钟到2015年双十一的8.59万笔/秒,蚂蚁金服的技术架构和运维体系一直都在不断摸索和实践.本文就"互联网IT运维体系"这一主题,和朋友们分享蚂蚁金服在该领域的实践经验. 从2010年支撑双十一最高交易峰值2万笔/分钟到2015年双十一的8.59万笔/秒,蚂蚁金服在技术架构和运维体系方面不断摸索实践所取得的成果.在这个过程中,以持续技术演进和创新来支撑互联网金融业务的飞

大卖家分享:跨境电商应重"商"轻"电"

广州资深卖家Hank.深圳大卖家夏昭.王冠军带来颇有参考价值的多渠道布局分享. 夏昭从2009年开始从事亚马逊,后来做了速卖通.wish等各种平台.王冠军的公司目前15人,年销售额接近千万美金. 夏昭说,很多人都是重电而轻商,去研究一些平台的规则和算法,试图找出一些漏洞和技巧,把自己的产品做起来."这个我不是很认可的,我认为所谓电商,一定要重商轻电,商永远要重,这意味着你做跨境电商还是做所谓的一切买卖本质是提供良好的产品给客户,所以产品是摆在非常重要的位置." "我做了一款移

由婚礼案例分享社区到O2O电商

摘要: 中国每年有1000万对新人,13年的婚嫁直接花费估计在5000亿人民币,这一数字将在今年增长到8000亿.滴着蜜糖.飘着甜香的婚礼大蛋糕,显然不会逃出互联网人的视线.美国著名的婚尚 中国每年有1000万对新人,13年的婚嫁直接花费估计在5000亿人民币,这一数字将在今年增长到8000亿.滴着蜜糖.飘着甜香的婚礼大蛋糕,显然不会逃出互联网人的视线.美国著名的婚尚公司XO集团(拥有美国在线交易额最大的婚礼网站)早在2010年就进入中国,推出婚嫁资讯网站"爱结网".而一批本土公司,如

Shopex电商云部门架构师张巍:商派电商云的分享

2012年10月25日~26日51CTO在北京工人体育场隆重举行2012云计算架构师峰会.当IT技术和互联网的发展催生出新的业务模式,当云计算作为一种新型的服务交付模式被越来越多的关注和意欲采用,惊喜.新奇.困惑.踌躇--这些情绪或许您正在拥有! [51CTO独家报道]不必苦恼,眼下有解.51CTO传媒紧跟时代发展的潮流,站在技术和模式变革的前沿,洞悉服务转型模式及架构搭建的困惑,51CTO于2012年10月25日~26日在北京工人体育场举办"2012云计算架构师峰会"将为您搭建一个与

百姓网的前端架构是怎样的?

其实我们的前端架构还远未成熟,可以说正在传统前端架构到现代前端架构的转变中,这个转变以引入构建系统为标志(虽然之前mobile版已经引入了stylus),从去年(2014)年初开始,预计可能持续2到3年时间达到一个我心目中理想的较稳定架构. 之所以预期如此长的时间,是因为总体上,对于前端构建.模块化.组件方案等非常基础和牵一发动全身的设施,我采取宁缺毋滥,看不清楚就先不上的保守策略--是不是看上去似乎和我在社区老是讲新技术的形象不太相符?^_^ 这种策略有三个原因. 第一是百姓网的性质是以信息流

云架构师前(钱)景这么好,我们该如何转型?这有两位阿里云云架构总监多年心得

当下,由于云计算具备在线(在线的价格.服务交付.管控运维和技术文档)等特点,很多场景下用户自己就能通过online的方式自助购买并使用云服务,但由于他们缺乏产品与解决方案层面的技术和决策能力,因此,不论是用户.还是云厂商对云架构师的依赖和需求都越来越大. 那什么是云架构师呢?或者咱们从起点出发--什么是云架构? 有些同学属于理论党,我们先来看看云架构的定义,维基里面的描述为: Cloud computing architecture refers to the components and su