[翻译]High Performance JavaScript(019)

第六章  Responsive Interfaces  响应接口

 

    There's nothing more frustrating than clicking something on a web page and having nothing happen. This problem goes back to the origin of transactional web applications and resulted in the now-ubiquitous "please click only once" message that accompanies most form submissions. A user's natural inclination is to repeat any action that doesn't result in an obvious change, and so ensuring responsiveness in web applications is an important performance concern.

    没有什么比点击页面上的东西却什么也没发生更令人感到挫折了。这个问题又回到了原始网页交互程序和现在已无处不在的提交表单时弹出的“请勿重复提交”消息上面。用户自然倾向于重复尝试这些不发生明显变化的动作,所以确保网页应用程序的响应速度也是一个重要的性能关注点。

 

    Chapter 1 introduced the browser UI thread concept. As a recap, most browsers have a single process that is shared between JavaScript execution and user interface updates. Only one of these operations can be performed at a time, meaning that the user interface cannot respond to input while JavaScript code is executed and vice versa. The user interface effectively becomes "locked" when JavaScript is executing; managing how long your JavaScript takes to execute is important to the perceived performance of a web application.

    第一节介绍了浏览器UI线程概念。总的来说,大多数浏览器有一个单独的处理进程,它由两个任务所共享:JavaScript任务和用户界面更新任务。每个时刻只有其中的一个操作得以执行,也就是说当JavaScript代码运行时用户界面不能对输入产生反应,反之亦然。或者说,当JavaScript运行时,用户界面就被“锁定”了。管理好JavaScript运行时间对网页应用的性能很重要。

 

The Browser UI Thread  浏览器UI线程

 

    The process shared by JavaScript and user interface updates is frequently referred to as the browser UI thread (though the term "thread" is not necessarily accurate for all browsers). The UI thread works on a simple queuing system where tasks are kept until the process is idle. Once idle, the next task in the queue is retrieved and executed. These tasks are either JavaScript code to execute or UI updates to perform, which include redraws and reflows (discussed in Chapter 3). Perhaps the most interesting part of this process is that each input may result in one or more tasks being added to the queue.

    JavaScript和UI更新共享的进程通常被称作浏览器UI线程(虽然对所有浏览器来说“线程”一词不一定准确)。此UI线程围绕着一个简单的队列系统工作,任务被保存到队列中直至进程空闲。一旦空闲,队列中的下一个任务将被检索和运行。这些任务不是运行JavaScript代码,就是执行UI更新,包括重绘和重排版(在第三章讨论过)。此进程中最令人感兴趣的部分是每次输入均导致一个或多个任务被加入队列。

 

    Consider a simple interface where a button click results in a message being displayed on the screen:

    考虑这样一个简单的接口:按下一个按钮,然后屏幕上显示出一个消息:

 

<html>
  <head>
    <title>Browser UI Thread Example</title>
  </head>
  <body>
    <button οnclick="handleClick()">Click Me</button>
    <script type="text/javascript">
      function handleClick(){
        var div = document.createElement("div");
        div.innerHTML = "Clicked!";
        document.body.appendChild(div);
      }
    </script>
  </body>
</html>

    When the button in this example is clicked, it triggers the UI thread to create and add two tasks to the queue. The first task is a UI update for the button, which needs to change appearance to indicate it was clicked, and the second is a JavaScript execution task containing the code for handleClick(), so that the only code being executed is this method and anything it calls. Assuming the UI thread is idle, the first task is retrieved and executed to update the button's appearance, and then the JavaScript task is retrieved and executed. During the course of execution, handleClick() creates a new <div> element and appends it to the <body> element, effectively making another UI change. That means that during the JavaScript execution, a new UI update task is added to the queue such that the UI is updated once JavaScript execution is complete. See Figure 6-1.

    当例子中的按钮被点击时,它触发UI线程创建两个任务并添加到队列中。第一个任务是按钮的UI更新,它需要改变外观以指示出它被按下了,第二个任务是JavaScript运行任务,包含handleClick()的代码,被运行的唯一代码就是这个方法和所有被它调用的方法。假设UI线程空闲,第一个任务被检查并运行以更新按钮外观,然后JavaScript任务被检查和运行。在运行过程中,handleClick()创建了一个新的<div>元素,并追加在<body>元素上,其效果是引发另一次UI改变。也就是说在JavaScript运行过程中,一个新的UI更新任务被添加在队列中,当JavaScript运行完之后,UI还会再更新一次。如图6-1。

Figure 6-1. UI thread tasks get added as the user interacts with a page

图6-1  用户与页面交互时向UI线程增加一条任务

 

    When all UI thread tasks have been executed, the process becomes idle and waits for more tasks to be added to the queue. The idle state is ideal because all user actions then result in an immediate UI update. If the user tries to interact with the page while a task is being executed, not only will there not be an immediate UI update, but a new task for a UI update may not even be created and queued. In fact, most browsers stop queuing tasks for the UI thread while JavaScript is executing, which means that it is imperative to finish JavaScript tasks as quickly as possible so as not to adversely affect the user's experience.

    当所有UI线程任务执行之后,进程进入空闲状态,并等待更多任务被添加到队列中。空闲状态是理想的,因为所有用户操作立刻引发一次UI更新。如果用户企图在任务运行时与页面交互,不仅没有即时的UI更新,而且不会有新的UI更新任务被创建和加入队列。事实上,大多数浏览器在JavaScript运行时停止UI线程队列中的任务,也就是说JavaScript任务必须尽快结束,以免对用户体验造成不良影响。

 

Browser Limits  浏览器限制

 

    Browsers place limits on the amount of time that JavaScript take to execute. This is a necessary limitation to ensure that malicious coders can't lock up a user's browser or computer by performing intensive operations that will never end. There are two such limits: the call stack size limit (discussed in Chapter 4) and the long-running script limit. The long-running script limit is sometimes called the long-running script timer or the runaway script timer, but the basic idea is that the browser keeps track of how long a script has been running and will stop it once a certain limit is hit. When the limit is reached, a dialog is displayed to the user, such as the one in Figure 6-2.

    浏览器在JavaScript运行时间上采取了限制。这是一个有必要的限制,确保恶意代码编写者不能通过无尽的密集操作锁定用户浏览器或计算机。此类限制有两个:调用栈尺寸限制(第四章讨论过)和长时间脚本限制。长运行脚本限制有时被称作长运行脚本定时器或者失控脚本定时器,但其基本思想是浏览器记录一个脚本的运行时间,一旦到达一定限度时就终止它。当此限制到达时,浏览器会向用户显示一个对话框,如图6-2所示。

Figure 6-2. Internet Explorer's long-running script warning dialog is displayed when more than 5
million statements have been executed

图6-2  Internet Explorer的长运行脚本警告对话框,当运行超过5百万条语句时显示

 

    There are two ways of measuring how long a script is executing. The first is to keep track of how many statements have been executed since the script began. This approach means that the script may run for different periods of time on different machines, as the available memory and CPU speed can affect how long it takes to execute a single statement. The second approach is to track the total amount of time that the script has been executing. The amount of script that can be processed within a set amount of time also varies based on the user's machine capabilities, but the script is always stopped after a set amount of time. Not surprisingly, each browser has a slightly different approach to long-running script detection:

    有两种方法测量脚本的运行时间。第一个方法是统计自脚本开始运行以来执行过多少语句。此方法意味着脚本在不同的机器上可能会运行不同的时间长度,可用内存和CPU速度可以影响一条独立语句运行所花费的时间。第二种方法是统计脚本运行的总时间。在特定时间内可运行的脚本数量也因用户机器性能差异而不同,但脚本总是停在固定的时间上。毫不奇怪,每个浏览器对长运行脚本检查方法上略有不同:

 

• Internet Explorer, as of version 4, sets a default limit of 5 million statements; this limit is stored in a Windows registry setting called HKEY_CURRENT_USER/Software/Microsoft/InternetExplorer/Styles/MaxScriptStatements.

  Internet Explorer,在第4版中,设置默认限制为5百万条语句;此限制存放在Windows注册表中,叫做

  HKEY_CURRENT_USER/Software/Microsoft/InternetExplorer/Styles/MaxScriptStatements


• Firefox has a default limit of 10 seconds; this limit is stored in the browser's configuration
settings (accessible by typing about:config in the address box) as the dom.max_script_run_time key.

  Firefox默认限制为10秒钟,此限制存放在浏览器的配置设置中(在地址栏中输入about:config)键名为dom.max_script_run_time。


• Safari has a default limit of 5 seconds; this setting cannot be altered, but you can disable the timer by enabling the Develop menu and selecting Disable Runaway JavaScript Timer.

  Safari默认限制为5秒钟,此设置不能改变,但你可以关闭此定时,通过启动Develop菜单并选择“禁止失控JavaScript定时器”。


• Chrome has no separate long-running script limit and instead relies on its generic
crash detection system to handle such instances.

  Chrome没有独立的长运行脚本限制,替代以依赖它的通用崩溃检测系统来处理此类实例。


• Opera has no long-running script limit and will continue to execute JavaScript code until it has finished, though, due to Opera's architecture, this will not cause system instability while the execution is completed.

  Opera没有长运行脚本限制,将继续运行JavaScript代码直至完成,由于Opera的结构,当运行结束时它并不会导致系统不稳定。

 

    When the browser's long-running script limit is reached, a dialog is displayed to the user, regardless of any other error-handling code on the page. This is a major usability issue because most Internet users are not technically savvy and would therefore be confused about the meaning of the error message as well as which option (to stop the script or allow it to continue) is appropriate.

    当浏览器的长时间脚本限制被触发时,有一个对话框显示给用户,而不管页面上的任何其他错误处理代码。这是一个主要的可用性问题,因为大多数互联网用户并不精通技术,会被错误信息所迷惑,不知道应该选择哪个选项(停止脚本或允许它继续运行)。

 

    If your script triggers this dialog in any browser, it means the script is simply taking too long to complete its task. It also indicates that the user's browser has become unresponsive to input while the JavaScript code is continuing to execute. From a developer's point of view, there is no way to recover from a long-running script dialog's appearance; you can't detect it and therefore can't adjust to any issues that might arise as a result. Clearly, the best way to deal with long-running script limits is to avoid them in the first place.

    如果你的脚本在浏览器上触发了此对话框,意味着脚本只是用太长的时间来完成任务。它还表明用户浏览器在JavaScript代码继续运行状态下无法响应输入。从开发者观点看,没有办法改变长运行脚本对话框的外观,你不能检测到它,因此不能用它来提示可能出现的问题。显然,长运行脚本最好的处理办法首先是避免它们。

 

How Long Is Too Long?  多久才算“太久”?

 

    Just because the browser allows a script to continue executing up to a certain number of seconds doesn't mean you should allow it do so. In fact, the amount of time that your JavaScript code executes continuously should be much smaller than the browser-imposed limits in order to create a good user experience. Brendan Eich, creator of JavaScript, is quoted as having once said, "[JavaScript] that executes in whole seconds is probably doing something wrong…."

    浏览器允许脚本继续运行直至某个固定的时间,这并不意味着你可以允许它这样做。事实上,你的JavaScript代码持续运行的总时间应当远小于浏览器实施的限制,以创建良好的用户体验。Brendan Eich,JavaScript的创造者,引用他的话说,“[JavaScript]运行了整整几秒钟很可能是做错了什么……”

 

    If whole seconds are too long for JavaScript to execute, what is an appropriate amount of time? As it turns out, even one second is too long for a script to execute. The total amount of time that a single JavaScript operation should take (at a maximum) is 100 milliseconds. This number comes from research conducted by Robert Miller in 1968. Interestingly, usability expert Jakob Nielsen noted in his book Usability Engineering (Morgan Kaufmann, 1994) that this number hasn't changed over time and, in fact, was reaffirmed in 1991 by research at Xerox-PARC.

    如果整整几秒钟对JavaScript运行来说太长了,那么什么是适当的时间?事实证明,即使一秒钟对脚本运行来说也太长了。一个单一的JavaScript操作应当使用的总时间(最大)是100毫秒。这个数字根据Robert Miller在1968年的研究。有趣的是,可用性专家Jakob Nielsen在他的著作《可用性工程》(Morgan Kaufmann,1944)上注释说这一数字并没有因时间的推移而改变,而且事实上在1991年被Xerox-PARC(施乐公司的帕洛阿尔托研究中心)的研究中重申。

 

    Nielsen states that if the interface responds to user input within 100 milliseconds, the user feels that he is "directly manipulating the objects in the user interface." Any amount of time more than 100 milliseconds means the user feels disconnected from the interface. Since the UI cannot update while JavaScript is executing, the user cannot feel in control of the interface if that execution takes longer than 100 milliseconds.

    Nielsen指出如果该接口在100毫秒内响应用户输入,用户认为自己是“直接操作用户界面中的对象。”超过100毫秒意味着用户认为自己与接口断开了。由于UI在JavaScript运行时无法更新,如果运行时间长于100毫秒,用户就不能感受到对接口的控制。

 

    A further complication is that some browsers won't even queue UI updates while JavaScript is executing. For example, if you click a button while some JavaScript code is executing, the browser may not queue up the UI update to redraw the button as pressed or any JavaScript initiated by the button. The result is an unresponsive UI that appears to "hang" or "freeze."

    更复杂的是有些浏览器在JavaScript运行时不将UI更新放入队列。例如,如果你在某些JavaScript代码运行时点击按钮,浏览器可能不会将重绘按钮按下的UI更新任务放入队列,也不会放入由这个按钮启动的JavaScript任务。其结果是一个无响应的UI,表现为“挂起”或“冻结”。

 

    Each browser behaves in roughly the same way. When a script is executing, the UI does not update from user interaction. JavaScript tasks created as a result of user interaction during this time are queued and then executed, in order, when the original JavaScript task has been completed. UI updates caused by user interaction are automatically skipped over at this time because the priority is given to the dynamic aspects of the page. Thus, a button clicked while a script is executing will never look like it was clicked, even though its onclick handler will be executed.

    每种浏览器的行为大致相同。当脚本执行时,UI不随用户交互而更新。此时JavaScript任务作为用户交互的结果被创建被放入队列,然后当原始JavaScript任务完成时队列中的任务被执行。用户交互导致的UI更新被自动跳过,因为优先考虑的是页面上的动态部分。因此,当一个脚本运行时点击一个按钮,将看不到它被按下的样子,即使它的onclick句柄被执行了。

 

    Even though browsers try to do something logical in these cases, all of these behaviors lead to a disjointed user experience. The best approach, therefore, is to prevent such circumstances from occurring by limiting any JavaScript task to 100 milliseconds or less. This measurement should be taken on the slowest browser you must support (for tools that measure JavaScript performance, see Chapter 10).

    尽管浏览器尝试在这些情况下做一些符合逻辑的事情,但所有这些行为导致了一个间断的用户体验。因此最好的方法是,通过限制任何JavaScript任务在100毫秒或更少时间内完成,避免此类情况出现。这种测量应当在你要支持的最慢的浏览器上执行(关于测量JavaScript性能的工具,参见第十章)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值