可简单避免的三个 JavaScript 发布错误
Web应用程序开发是倾向于在客户端运行所有用户逻辑和交互代码,让服务器暴露REST或者RPC接口。编译器是针对JS作为一个平台,第二版ECMAScript正是考虑到这一点在设计。客户端框架例如Backbone, Ember和Require鼓励创建功能丰富的应用程序,不仅有丰富的代码,而且各个组件,组件与数据之间有很多相互作用。
这真的很好,或许还能产生一些优秀的用户体验,但是毫无疑问的是,这是很难开发web应用程序和web页面。
根本原因是在互联网上服务你的代码和数据,运行在一些随机的浏览器上,在javascript中,这是一种你需要特别小心的语言,它是一个完全缺乏代码部署的平台。而且它不会很快就得到改善。我觉得如果星际迷航是现实生活,那么Jean-Luc Picard队长每隔一段时间不能打架的原因是他仍然是克林仪表板加载。
我想强调的是三个相对常见的错误和容易的解决方案,并且谈谈一些我们遇到的从ReadyForZero学到的特别的事情。
1、剥离“缓存清除”头信息
你可能使用CDN来缓存静态资源,这当然是合理的。如果你向服务器请求非缓存的资源(比如在AWS<Amazon Web Service>端使用"custom-origin"将文件指向真实的网络站点),这就需要小心了。你可能会在部署新版本的文件后添加一段缓存清除的字符串(头信息)到文件名上来达到这个目的,这样你的文件名看起来是这样的:
http://example.com/js/main__V0123456789abcdef__.js
这很容易做到,你可以选择任意的Hash算法来生成一段指纹信息作为这个字符串,这样它就会随着文件内容变化而变化。当新的url被引用时,它不可能被缓存,这样就可以获取到服务器上的新版本。错误就发生在这里。在网络上有很多都建议剥离“缓存清除”头信息,而是让你的服务器直接提供新版本的文件。如果你有多台服务器集群这可能导致你的站点上不同文件(如:html、js)的版本不一致(如js已更新但是html(从另一台服务器请求)仍然是旧的),不仅如此,更严重是它很容易导致CDN缓存了错误的版本。这个错误是这样发生的:
- 初始阶段,所有的服务器都是HTML1 和JS1.
- 服务器A重启了,并提供HTML2和JS2.
- 一个客户端向CDN请求main__V2__.js,这个时候这个文件是新的所以CDN上没有缓存。
- CDN把这个请求传给了你设置的custom origin, 碰巧这个请求发到了服务器B上。
- 服务器B剥离了“缓存清除”字符串并返回旧的版本。
- CDN把旧版的的文件当新的缓存了。
这件事情考虑起来很简单明了,但是盲目的听从网络上的建议很可能导致错误。更糟糕的是在你这看起来一切都是好的你根本不知道发生了错误,但是其它地区的用户使用了不同CDN很可能缓存了错误的版本。解决方案是不要剥离“缓存清除”字符串并将静态资源存放在能够正确支持各个版本的地方
2. 处理庞大的JS炸弹
每个人都知道,我们需要压缩我们的javascript文件,并把它们连接在一起。但是盲目地这样做并非明智之举。如果连接的文件很大,那么更有效的方法就是并行化。另外,如果你需要频繁的修改文件的某一部分,你可能会导致很多地方失效,而文件很大部分却没有被修改过。
如果把频繁修改的部分分离出来,那么就可以解决两边的问题。我建议使用require.js - 它可以实现对你的javascript的真正的依赖关系管理,而且第一次使用的时候,设置很简单(稍后添加会很痛苦),而且可以帮助你理解和管理依赖关系,包括一些高级选项,例如异步载入。
需要注意的:require.js会等待一段时间后会放弃载入资源,这个可以通过指定waitSeconds选项实现,这个选项的默认值似乎7秒,它依赖于你的用户在哪里(例如:手机),可以是很短的时间。
3. 没有汇总错误事件
你不能只让你的javascript上线使用,而不关心它的运行情况。你不可能测试每一个浏览器和每个用户的状态组合。另外,不同的载入时间可能导致怪异的状态。所以,建立某种反馈机制来判断你的用户是否遇到错误,变得十分重要。这很简单,你只需通过指定一个全局错误处理程序,收集错误,并发送会服务器。以下是一个例子:
window.onerror = function(message, url, linenumber) {
sendToServer({message: message, line: linenumber, url: url});
}
棘手的部分是,很多时候会出现一些非0的错误,因为用户可能安装了各种怪异的插件或者其他。所以你需要跟踪稳定的状态到底是什么,还有是否有任何的偏差。
ReadyForZero,我们在顶层捕获onError事件,并把它们发送会服务器,然后生成一个日报,汇总多少个用户发生了错误,和这些错误发生在哪里。我们发现很多时候,错误消息并不足够,所以我们同样需要从我们的事件系统回传最后几个事件。通过分析用户最近触发的Backbone或者JQuery事件,对于获取当时用户触发错误时候的上下文信息,有很大的帮助。
唾手可得的改进
令人沮丧的是下面这些点不是我们必须担心的。公司更应该关注在产品上,快速高质量地把它们弄出来。但是请记住如果这些垂首可得的改进获得实施,你将能更专注于大动作上。
人们总是被一些琐事纠缠住花费了大量时间,但是仅仅让你的应用正常运行就能获得大的成长。
1,你的客户端代码有没有内存泄露?你确定吗?你是怎么知道的?
2,在ReadyForZero[注1]我们有很多聪明的人们致力于推动这门艺术。
[注1]ReadyForZero:是由 Y Combinator资助的一家公司,公司的目的是通过网络平台帮助消费者摆脱信用卡债务。
英文原文:3 Javascript deployment mistakes that are simple to avoid
可简单避免的三个 JavaScript 发布错误的更多相关文章
- NetMQ(三): 发布订阅模式 Publisher-Subscriber
ZeroMQ系列 之NetMQ 一:zeromq简介 二:NetMQ 请求响应模式 Request-Reply 三:NetMQ 发布订阅模式 Publisher-Subscriber 四:NetMQ ...
- Front End Developer Questions 前端开发人员问题(三)JavaScript部分
问题来源:http://markyun.github.io/2015/Front-end-Developer-Questions/ 三.javascript1.介绍JavaScript的基本数据类型. ...
- JavaWeb和WebGIS学习笔记(三)——GeoServer 发布shp数据地图
系列链接: Java web与web gis学习笔记(一)--Tomcat环境搭建 Java web与web gis学习笔记(二)--百度地图API调用 JavaWeb和WebGIS学习笔记(三)-- ...
- 三款Javascript SPAs框架资料整理和总结
一.框架介绍 RequireJS 资料:http://www.requirejs.cn/RequireJS的目标是鼓励代码的模块化,它使用了不同于传统<script>标签的脚本加载步骤.可 ...
- iOS开发UI篇—Quartz2D简单使用(三)
iOS开发UI篇—Quartz2D简单使用(三) 一.通过slider控制圆的缩放 1.实现过程 新建一个项目,新建一个继承自UIview的类,并和storyboard中自定义的view进行关联. 界 ...
- 第三章 JavaScript操作BOM对象
第三章 JavaScript操作BOM对象 一.window对象 浏览器对象模型(BOM)是javascript的组成之一,它提供了独立与浏览器窗口进行交换的对象,使用浏览器对象模型可以实现与HT ...
- 前端开发【第三篇: JavaScript基础】
JavaScript是一门编程语言,浏览器内置了JavaScript语言的解释器,所以在浏览器上按照JavaScript语言的规则编写相应代码之,浏览器可以解释并做出相应的处理. 一.如何编写 1.J ...
- 简单的页面互点Javascript代码
简单的页面互点Javascript代码,可以适用于前端$(function(){ $('.ip_b_con_item li,.pro_index_list li').mouseover(functio ...
- XML系列之--对电文格式XML的简单操作(三)
前两章介绍了关于Linq创建.解析SOAP格式的XML,在实际运用中,可能会对xml进行一些其它的操作,比如基础的增删该查,而操作对象首先需要获取对象,针对于DOM操作来说,Linq确实方便了不少,如 ...
随机推荐
- CANOpen的几种操作以及数据
其实3年前在21ic就准备做这篇文章了,那时,CANOpen也只是刚刚在国内推广,所以几乎没有项目用到.现在有了实际的项目,完全确认了以前移植和测试的代码,所以列举一些CANOpen的底层操作以及数据 ...
- pxe前期网络准备
核心交换机:[H3C12510-HEXIN]vlan 3010 //如果存在则不需要创建[H3C12510-HEXIN]dis interface Bridge-Aggregation brief / ...
- 【Leetcode】109. Convert Sorted List to Binary Search Tree
Question: Given a singly linked list where elements are sorted in ascending order, convert it to a h ...
- 数组 javaScript权威指南笔记
创建数组 var a=[1,2,3,4] var arr=new Array() var arr=new Array(10);//创建长度为10的数组 var arr=new Array(1,2, ...
- how to know iframe is loaded in js
how to know iframe is loaded in js ??? iframe & HTTPS & CORS https://iframe.xgqfrms.xyz/eapp ...
- 【Python】Python基础
源程序文件通常以.py为扩展名 #!/usr/bin/python shebang,即执行脚本时通知内容要启动的解释器 import platform 导入模块 print platform.unam ...
- ognl用法 取变量时候 需要在变量前面加上# 取字符串需要用单引号包裹字符串
- AtCoder Regular Contest 081
C - Make a Rectangle 从大到小贪心即可. # include <bits/stdc++.h> using namespace std; map<int,int&g ...
- QComboBox 树形视图选择
QComboBox 控件支持树形图显示. A. void QComboBox::setModel(QAbstractItemModel *model): B. void QComboBox::se ...
- BZOJ3156 防御准备(动态规划+斜率优化)
设f[i]为在i放置守卫塔时1~i的最小花费.那么显然f[i]=min(f[j]+(i-j)*(i-j-1)/2)+a[i]. 显然这是个斜率优化入门题.将不与i.j同时相关的提出,得f[i]=min ...