前端跨站技术
随着前端技术栈在服务端和移动端上的尝试和日益成熟,前端工程师的追求绝不只是页面上的技术,如何实现跨服务端,如何扩展到移动端开发将变成主要讨论议题。
JavaScript跨后端实现技术
前端通过与Node(基于事件驱动和无阻塞)结合的开发模式越来越被开发者认同并在越来越多的项目中得到实现。
SPA场景下SEO的问题
SPA应用加载的基本流程:浏览器端先加载一个空页面和JavaScript脚本,然后异步请求接口获取数据,渲染页面数据内容后展示给用户。问题是:搜索引擎抓取页面解析该页面HTML中关键字、内容时JavaScript尚未调用执行,仅仅是一个空页面(body为空),影响搜索引擎收录页面的内容排行。解决方案:使用Node端数据渲染,在页面请求时将页面内容渲染到页面上输出(即,后台直出)。
前后端同构
实现核心:只开发一套项目代码,既可以用来实现前端的JavaScript加载渲染,也可以用于后台的直出渲染;
实现原理:(1)数据模板的前端渲染和后台直出;(2)MVVM的前端实现和后台直出;(3)Virtual DOM的前端渲染和后端直出。
基于数据模板的前后端同构
将模板描述语法与数据进行拼接生成HTML代码字符串插入到页面特定的元素中来完成数据的渲染。
基于MVVM的前后端同构
页面加载完成后会开始扫描DOM结构中的Directive指令并进行DOM操作渲染或事件绑定,所以数据的显示仍然需要页面执行Directive后才能完成。
基于Virtual DOM的前后端同构
在浏览器生成前端DOM结构,或在直出层直接转换成HTML文本字符串输出。Virtual DOM的逻辑实现仍然需要在浏览器端进行事件绑定来完成,最好让同构框架帮助我们自动完成,根据HTML的结构进行特定的事件绑定处理,保证最后展示给用户的页面完整且带有交互逻辑。
对于模板前后端都需要转化成HTML文本,然后生成DOM;对于MVVM(ViewModel)或者Virtual DOM,前端直接生成DOM,后端需要转化成HTML文本,然后生成DOM。
使用前后端同构实现方案,需要注意的几个问题:
- 前后端构架的选择:这主要指前端使用的主要框架和后端结构渲染解析模块的选择;
- 模块渲染机制:关键的不同点在于HTML描述和转化方式的选择上面;
- 构建打包:同一套代码基于前后端场景打包完成后是不一样的,同时需要将打包后的内容输出到不同目录,便于调试;
- 渲染和直出区分:必须方便的选择使用前端渲染的方式还是后台直出的方式,例如在URL后面添加render参数进行区分。
跨终端设计与实现
Hybrid技术趋势
随着移动互联网的发展,Native应用快速迭代开发的需求也越来越多,但是现有Native应用的开发迭代速度依然无法满足市场快速变化的需求;伴随着H5的出现,其允许开发者在移动设备上快速开发网页端应用,进入了Native应用、Web应用和Hybrid应用并存时代。
Native应用的优点
- 原生系统级Native API的支持,运行速度快、性能好,可使用原生Native动画库;
- 可针对不同平台特性进行用户体验优化;
- 资源在打包安装时生成,节省用户使用时的流量。
Native应用的缺点
- 开发成本高,兼容性差;维护成本高,需要手动下载更新,历史版本也要维护;
- 上线需要应用商店审核;版本更新慢,更新时需要重新下载安装包;
- 应用界面的内容不可被搜索引擎检索。
Web应用的优点
- 跨平台和终端,基于浏览器或WebView运行,开发成本低 ;
- 部署简单,快捷,无需安装;迭代速度快;
- 内容可被搜索引擎检索。
Web应用的缺点
- 消息推送、动画等实现方式较差,浏览体验无法超过Native应用;
- 不能调用设备的原生特性,如无法访问本地资源、相机API等。
Hybrid应用的优点
- 集结了上述二者的优点;
- 可通过JSBridge调用设备的系统级API;
- 借助于MNV*的开发模式可以更接近Native应用的用户体验。
Hybrid应用的缺点
- 部分机型兼容相对Native较差,但比Web体验更好。
基于localStorage的资源离线和更新技术
ServiceWorker的资源离线与更新
ServiceWorker是替代Application Cache的机制,目前为止其兼容性很差。
localStorage资源离线缓存与更新
基本思路:将JavaScript、CSS资源文件甚至是接口返回的数据资源缓存到浏览器的localStorage中,下次打开页面时不进行JavaScript、CSS资源的请求,而是直接通过localStorage读取内容,然后插入到页面中解析执行。
<div id="versionStore" data-version="2"></div>
/** * localStorage方式实现增量更新 */
let localStorage = window.localStorage,
oldVersion = localStorage.getItem('version') || 0, // version记录localStorage中存的版本
newVersion = +document.querySelector('#versionStore').getAttribute('data-version'); // 当前最新版本
let content = null;
if(newVersion > oldVersion) {
// 内容有更新或第一次加载
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(event){
if (xhr.readyState == 4){
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
content = xhr.responseText;
updateScript(content); // 更新脚本
localStorage.setItem('version', newVersion); // 更新本地版本
localStorage.setItem('a.js', content); // 更新本地内容
}
}
};
xhr.open("get", "index.js", true);
xhr.send(null);
} else {
// 无内容更新
content = localStorage.getItem('a.js'); // 直接获取本地内容
updateScript(content)
}
/** * 更新页面脚本 * @param content 脚本内容 */
function updateScript(content) {
let script = document.createElement('script');
script.innerHTML = content;
document.body.appendChild(script);
script = null;
}
页面脚本通过获取页面上的“最新版本号”和本地localStorage保存的“旧版本号”进行对比。如果本地没有版本号或者版本号较旧,则加载最新版本的静态资源文件到页面上,同时更新本地原有的localStorage缓存的内容和版本号;否则直接读取localStorage的静态资源内容到页面中解析执行。
缺点:(1)localStorage的大小限制,同域下一般是5MB;(2)用户手动清空localStorage会使离线资源失效;(3)读取localStorage的速度比较慢,尤其是移动端。
基于增量文件的更新方式
如果一个文件中只修改了少量字符,上述方式会导致整个资源文件的更新。为了节省流量我们需要增量更新。假设我们已有1.1,1.2,1.3三个版本发布,现在需要进行1.4的发布上线。为了满足增量更新,我们需要根据前面的三个版本文件内容与最新版本内容进行对比分析,分别生成三个不同版本的增量文件1.1-1.4.js,1.2-1.4.js,1.3-1.4.js,同时保留1.4版本的全量文件。
// 实现方式跟上述类似,只需修改请求地址
xhr.open("get", `${oldVersion}-${newVersion}.js`, true);
缺点:同时需要在服务器端,每次新版本发布维护多个增量文件来适应不同的旧版本更新的需要。
基于文件代码分块的增量更新机制
根据大小确定分割字符数(比如10个字符),文件字符串由几个字符串块连接组成chunk1-chunk2-chunk3-chunk4,此时需要在chunk1和chunk2之间添加data1,chunk3内容修改为chunk5,chunk4的块被删除。
[1, data1, 2, chunk5, -4]
1表示原来chunk1的内容不变,data1表示插入的新内容;-4表示删除chunk4的文件块;
let a = 1, b = 1; console.log(a, b);
// 修改为
let a = 2, b = 2; console.log(a + b);
基于编辑距离的增量更新机制
上面方式节约资源的量取决于块的大小和内容变化的块序号分布。根据编辑距离算法增量更新的方式可以真正做到字符级别的更新。它指的是从一个字符串变换到另一个字符串所需要的最少变化操作步骤。如果能计算获取两个文件对比变化时每个字符的操作步骤,就可以将操作步骤作为增量文件下载,然后在浏览器端进行代码的运算更新了。不过这种情况对于少量的字符更新很有用,如果一次更新的内容很多,生成的增量文件很可能比源文件还大,所以实际使用过程中需要结合具体情况,在上述两种增量方式中选择。
资源覆盖率统计
有了前端资源的离线和更新机制,就要考虑在每次新资源包发布后统计新版本的更新覆盖率。这对于增量更新尤为重要,如果发现某个版本的使用为0或接近0,该版本就无需在维护。方式有很多中,最简单的就是上报版本号,每次PV统计时带上版本号,最后根据PV中的版本号来统计访问不同版本上用户的分布情况。
未来前端时代
当MVVM、Virtual DOM或同构等技术实践都有很成熟高效的框架和方案可以实现时,对于移动端应用,前端可能会进入MNV*的原生NativeView开发,达到使用前端技术栈可以独立开发Native的能力;与此同时,我们需要关注物联网Web(3D展示)、Web VR(VR展示),人工智能必定成为前端一下批革命技术,把握技术发展趋势,紧跟邻域前进的步伐。
作为一个技术者,不要脱离实际项目去谈论技术!技术研究应该是在完成并希望将产品打造更好的目的上进行,切记过分追求技术!我们需要更多的产品思维,即把自己当成普通用户来对产品进行思考。高效率的开发、低成本的维护、卓越的性能、良好的扩展性将是我们不断奋斗的目标!