[翻译]High Performance JavaScript(024)

Data Format Conclusions  数据格式总结

 

    Favor lightweight formats in general; the best are JSON and a character-delimited custom format. If the data set is large and parse time becomes an issue, use one of these two techniques:

    总的来说越轻量级的格式越好,最好是JSON和字符分隔的自定义格式。如果数据集很大或者解析时间成问题,那么就使用这两种格式之一:

 

• JSON-P data, fetched using dynamic script tag insertion. This treats the data as executable JavaScript, not a string, and allows for extremely fast parsing. This can be used across domains, but shouldn't be used with sensitive data.

  JSON-P数据,用动态脚本标签插入法获取。它将数据视为可运行的JavaScript而不是字符串,解析速度极快。它能够跨域使用,但不应涉及敏感数据。

 

• A character-delimited custom format, fetched using either XHR or dynamic script tag insertion and parsed using split(). This technique parses extremely large datasets slightly faster than the JSON-P technique, and generally has a smaller file size.

  字符分隔的自定义格式,使用XHR或动态脚本标签插入技术提取,使用split()解析。此技术在解析非常大数据集时比JSON-P技术略快,而且通常文件尺寸更小。

 

    The following table and Figure 7-1 show all of the performance numbers again (in order from slowest to fastest), so that you can compare each of the formats in one place. HTML is excluded, since it isn't directly comparable to the other formats.

    下表和图7-1再次显示了所有方法的性能数据(按照从慢到快的顺序),你可以在此比较每种格式的优劣。HTML未包括,因为它与其他格式不能直接比较。

 



Figure 7-1. A comparison of data format download and parse times

图7-1  各种数据格式下载和解析的时间

 

    Keep in mind that these numbers are from a single test run in a single browser. The results should be used as general indicators of performance, not as hard numbers. You can run these tests yourself at http://techfoolery.com/formats/.

    请注意,这些数据只是在一个浏览器上进行一次测试获得的。此结果可用作大概的性能指标,而不是确切的数字。你可以自己运行这些测试,位于:http://techfoolery.com/formats/

 

Ajax Performance Guidelines  Ajax性能向导

 

    Once you have selected the most appropriate data transmission technique and data format, you can start to consider other optimization techniques. These can be highly situational, so be sure that your application fits the profile before considering them.

    一旦你选择了最合适的数据传输技术和数据格式,那么就开始考虑其他的优化技术吧。这些技术要根据具体情况使用,在考虑它们之前首先应确认你的应用程序是否能够适合这些概念。

 

Cache Data  缓存数据

 

    The fastest Ajax request is one that you don't have to make. There are two main ways of preventing an unnecessary request:

    最快的Ajax请求就是你不要用它。有两种主要方法避免发出一个不必要的请求:

 

• On the server side, set HTTP headers that ensure your response will be cached in the browser.

  在服务器端,设置HTTP头,确保返回报文将被缓存在浏览器中。


• On the client side, store fetched data locally so that it doesn't have be requested again.

  在客户端,于本地缓存已获取的数据,不要多次请求同一个数据。

 

    The first technique is the easiest to set up and maintain, whereas the second gives you the highest degree of control.

    第一种技术最容易设置和维护,而第二个给你最大程度的控制。

 

Setting HTTP headers  设置HTTP头

 

    If you want your Ajax responses to be cached by the browser, you must use GET to make the request. But simply using GET isn't sufficient; you must also send the correct HTTP headers with the response. The Expires header tells the browser how long a response can be cached. The value is a date; after that date has passed, any requests for that URL will stop being delivered from cache and will instead be passed on to the server. Here is what an Expires header looks like:

    如果你希望Ajax响应报文能够被浏览器所缓存,你必须在发起请求时使用GET方法。但这还不充分,你必须在响应报文中发送正确的HTTP头。Expires头告诉浏览器应当缓存响应报文多长时间。其值是一个日期,当过期之后任何对该URL发起的请求都不再从缓存中获得,而要重新访问服务器。一个Expires头如下:

 

Expires: Mon, 28 Jul 2014 23:30:00 GMT

    This particular Expires header tells the browser to cache this response until July 2014. This is called a far future Expires header, and it is useful for content that will never change, such as images or static data sets.

    这种特殊的Expires头告诉浏览器缓存此响应报文直到2014年7月。这就是所谓的遥远未来Expires头,用于那些永不改变的内容,例如图片和静态数据集。

 

    The date in an Expires header is a GMT date. It can be set in PHP using this code:

    Expires头中的日期是GMT日期。它在PHP中使用如下代码设置:

 

$lifetime = 7 * 24 * 60 * 60; // 7 days, in seconds.
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $lifetime) . ' GMT');

    This will tell the browser to cache the file for 7 days. To set a far future Expires header, set the lifetime to something longer; this example tells the browser to cache the file for 10 years:

    这将告诉浏览器缓存此数据7天。要设置一个遥远未来Expires头,将它的生命期设得更长,下面的例子告诉浏览器缓存文件10年:

 

$lifetime = 10 * 365 * 24 * 60 * 60; // 10 years, in seconds.
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $lifetime) . ' GMT');

    An Expires header is the easiest way to make sure your Ajax responses are cached on the browser. You don't have to change anything in your client-side code, and can continue to make Ajax requests normally, knowing that the browser will send the request on to the server only if the file isn't in cache. It's also easy to implement on the server side, as all languages allow you to set headers in one way or another. This is the simplest approach to ensuring your data is cached.

    一个Expires头是确保浏览器缓存Ajax响应报文最简单的方法。你不需要改变客户端的任何代码,可继续正常地使用Ajax请求,确信浏览器只当文件不在缓存之中时才将请求发送给服务器。这在服务器端也很容易实现,所有的语言都允许你通过某种方法设置信息头。这是保证你的数据被缓存的最简单方法。

 

Storing data locally  本地存储数据

 

    Instead of relying on the browser to handle caching, you can also do it in a more manual fashion, by storing the responses you receive from the server. This can be done by putting the response text into an object, keyed by the URL used to fetch it. Here is an example of an XHR wrapper that first checks to see whether a URL has been fetched before:

    除了依赖浏览器处理缓存之外,你还可以用手工方法实现它,直接存储那些从服务器收到的响应报文。可将响应报文存放在一个对象中,以URL为键值索引它。这是一个XHR封装,它首先检查一个URL此前是否被取用过:

 

var localCache = {};
function xhrRequest(url, callback) {
  // Check the local cache for this URL.
  if (localCache[url]) {
    callback.success(localCache[url]);
    return;
  }
  // If this URL wasn't found in the cache, make the request.
  var req = createXhrObject();
  req.onerror = function() {
    callback.error();
  };
  req.onreadystatechange = function() {
    if (req.readyState == 4) {
      if (req.responseText === '' || req.status == '404') {
        callback.error();
        return;
      }
      // Store the response on the local cache.
      localCache[url] = req.responseText;
      callback.success(req.responseText);
    }
  };
  req.open("GET", url, true);
  req.send(null);
}

    Overall, setting an Expires header is a better solution. It's easier to do and it caches responses across page loads and sessions. But a manual cache can be useful in situations where you want to be able to programmatically expire a cache and fetch fresh data. Imagine a situation where you would like to use cached data for every request, except when the user takes an action that causes one or more of the cached responses to become invalid. In this case, removing those responses from the cache is trivial:

    总的来说,设置一个Expires头是更好的解决方案。这比较容易,而且其缓存内容可以跨页面或者跨对话。而一个手工缓存可以用程序废止缓存内容并获取新的数据。设想一种情况,你为每个请求缓存数据,用户可能触发某些动作导致一个或多个响应报文作废。这种情况下从缓存中删除报文十分简单:

 

delete localCache['/user/friendlist/'];
delete localCache['/user/contactlist/'];

    A local cache also works well for users browsing on mobile devices. Most of the browsers on such devices have small or nonexistent caches, and a manual cache is the best option for preventing unnecessary requests.

    本地缓存也可很好地工作于移动设备上。此类设备上的浏览器缓存小或者根本不存在,手工缓存成为避免不必要请求的最佳选择。

 

Know the Limitations of Your Ajax Library  了解Ajax库的限制

 

    All JavaScript libraries give you access to an Ajax object, which normalizes the differences between browsers and gives you a consistent interface. Most of the time this is a very good thing, as it allows you to focus on your project rather than the details of how XHR works in some obscure browser. However, in giving you a unified interface, these libraries must also simplify the interface, because not every browser implements each feature. This prevents you from accessing the full power of XMLHttpRequest.

    所有JavaScript库允许你访问一个Ajax对象,它屏蔽浏览器之间的差异,给你一个一致的接口。大多数情况下这非常好,因为它使你可以关注你的项目,而不是那些古怪的浏览器上XHR的工作细节。然而,为了给你一个统一的接口,这些库必须简化接口,因为不是所有浏览器都实现了每个功能。这使得你不能访问XMLHttpRequest的完整功能。

 

    Some of the techniques we covered in this chapter can be implemented only by accessing the XHR object directly. Most notable of these is the streaming feature of multipart XHR. By listening for readyState 3, we can start to slice up a large response before it's completely received. This allows us to handle pieces of the response in real time, and it is one of the reasons that MXHR improves performance so much. Most JavaScript libraries, though, do not give you direct access to the readystatechange event. This means you must wait until the entire response is received (which may be a considerable amount of time) before you can start to use any part of it.

    本章中介绍的一些技术只能通过直接访问XHR对象实现。值得注意的是在多部分XHR技术中要用到流功能。通过监听readyState 3,我们在一个大的响应报文没有完全接收之前就开始解析它。这使我们可以实时处理报文片断,这也是MXHR能够大幅度提高性能的原因之一。不过大多数JavaScript库不允许你直接访问readystatechange事件。这意味着你必须等待整个响应报文接收完(可能是一个相当长的时间)然后你才能使用它。


    Using the XMLHttpRequest object directly is not as daunting as it seems. A few quirks aside, the most recent versions of all major browsers support the XMLHttpRequest object in the same way, and all offer access to the different readyStates. You can support older versions of IE with just a few more lines of code. Here is an example of a function that will return an XHR object, which you can then interact with directly (this is a modified version of what the YUI 2 Connection Manager uses):

    直接使用XMLHttpRequest对象并非像它看起来那么恐怖。除一些个别行为之外,所有主流浏览器的最新版本均以同样方式支持XMLHttpRequest对象,均可访问不同的readyStates。如果你要支持老版本的IE,只需要多加几行代码。下面例子中的函数返回一个XHR对象,你可以直接调用(这是YUI 2连接管理器中修改后的版本):


function createXhrObject() {
  var msxml_progid = [
    'MSXML2.XMLHTTP.6.0',
    'MSXML3.XMLHTTP',
    'Microsoft.XMLHTTP', // Doesn't support readyState 3.
    'MSXML2.XMLHTTP.3.0', // Doesn't support readyState 3.
  ];
  var req;
  try {
    req = new XMLHttpRequest(); // Try the standard way first.
  }
  catch(e) {
    for (var i = 0, len = msxml_progid.length; i < len; ++i) {
      try {
        req = new ActiveXObject(msxml_progid[i]);
        break;
      }
      catch(e2) { }
    }
  }
  finally {
    return req;
  }
}

    This will first try the versions of XMLHttp that do support readyState 3, and then fall back to the ones that don't in case those versions aren't available.

    它首先尝试支持readyState 3的XMLHttpRequest,然后回落到那些不支持此状态的版本中。

 

    Interacting directly with the XHR object also reduces the amount of function overhead, further improving performance. Just beware that by forgoing the use of an Ajax library, you may encounter some problems with older and more obscure browsers.

    直接操作XHR对象减少了函数开销,进一步提高了性能。只是放弃使用Ajax库,你可能会在古怪的浏览器上遇到一些问题。

 

Summary  总结

 

    High-performance Ajax consists of knowing the specific requirements of your situation and selecting the correct data format and transmission technique to match.

    高性能Ajax包括:知道你项目的具体需求,选择正确的数据格式和与之相配的传输技术。

 

    As data formats, plain text and HTML are highly situational, but they can save CPU cycles on the client side. XML is widely available and supported almost everywhere, but it is extremely verbose and slow to parse. JSON is lightweight and quick to parse (when treated as native code and not a string), and almost as interoperable as XML. Character-delimited custom formats are extremely lightweight and the quickest to parse for large datasets, but may take additional programming effort to format on the server side and parse on the client side.

    作为数据格式,纯文本和HTML是高度限制的,但它们可节省客户端的CPU周期。XML被广泛应用普遍支持,但它非常冗长且解析缓慢。JSON是轻量级的,解析迅速(作为本地代码而不是字符串),交互性与XML相当。字符分隔的自定义格式非常轻量,在大量数据集解析时速度最快,但需要编写额外的程序在服务器端构造格式,并在客户端解析。

 

    When requesting data, XHR gives you the most control and flexibility when pulling from the page's domain, though it treats all incoming data as a string, potentially slowing down the parse times. Dynamic script tag insertion, on the other hand, allows for cross-domain requests and native execution of JavaScript and JSON, though it offers a less robust interface and cannot read headers or response codes. Multipart XHR can be used to reduce the number of requests, and can handle different file types in a single response, though it does not cache the resources received. When sending data, image beacons are a simple and efficient approach. XHR can also be used to send large amounts of data in a POST.

    当从页面域请求数据时,XHR提供最完善的控制和灵活性,尽管它将所有传入数据视为一个字符串,这有可能降低解析速度。另一方面,动态脚本标签插入技术允许跨域请求和本地运行JavaScript和JSON,虽然它的接口不够安全,而且不能读取信息头或响应报文代码。多部分XHR可减少请求的数量,可在一次响应中处理不同的文件类型,尽管它不能缓存收到的响应报文。当发送数据时,图像灯标是最简单和最有效的方法。XHR也可用POST方法发送大量数据。

 

    In addition to these formats and transmission techniques, there are several guidelines that will help your Ajax appear to be faster:

    除这些格式和传输技术之外,还有一些准则有助于进一步提高Ajax的速度:

 

• Reduce the number of requests you make, either by concatenating JavaScript and CSS files, or by using MXHR.

  减少请求数量,可通过JavaScript和CSS文件打包,或者使用MXHR。

 

• Improve the perceived loading time of your page by using Ajax to fetch less important files after the rest of the page has loaded.

  缩短页面的加载时间,在页面其它内容加载之后,使用Ajax获取少量重要文件。

 

• Ensure your code fails gracefully and can handle problems on the server side.

  确保代码错误不要直接显示给用户,并在服务器端处理错误。

 

• Know when to use a robust Ajax library and when to write your own low-level Ajax code.

  学会何时使用一个健壮的Ajax库,何时编写自己的底层Ajax代码。

 

    Ajax offers one of the largest areas for potential performance improvements on your site, both because so many sites use asynchronous requests heavily and because it can offer solutions to problems that aren't even related to it, such as having too many resources to load. Creative use of XHR can be the difference between a sluggish, uninviting page and one that responds quickly and efficiently; it can be the difference between a site that users hate to interact with and one that they love.

    Ajax是提升你网站潜在性能之最大的改进区域之一,因为很多网站大量使用异步请求,又因为它提供了许多不相关问题的解决方案,这些问题诸如,需要加载太多资源。对XHR的创造性应用是如此的与众不同,它不是呆滞不友好的界面,而是响应迅速且高效的代名词;它不会引起用户的憎恨,谁见了它都会爱上它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值