<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://web.dev/</id>
  <title>Chris Wilson on web.dev</title>
  <updated>2026-04-15T23:21:06Z</updated>
  <author>
    <name>Chris Wilson</name>
  </author>
  <link href="https://web.dev/authors/chriswilson/feed.xml" rel="self"/>
  <link href="https://web.dev/"/>
  <icon>https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/RudCxfjPZlFSFeFRaYuG.png?auto=format</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  <subtitle>Google Developer Relations</subtitle>
  
  
  <entry>
    <title>Touch and mouse</title>
    <link href="https://web.dev/mobile-touchandmouse/"/>
    <updated>2013-03-13T00:00:00Z</updated>
    <id>https://web.dev/mobile-touchandmouse/</id>
    <content type="html" mode="escaped">&lt;h2 id=&quot;introduction&quot;&gt;Introduction &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/mobile-touchandmouse/#introduction&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For close to thirty years, desktop computing experiences have centered around a keyboard and a mouse or trackpad as our main user input devices. Over the last decade, however, smartphones and tablets have brought a new interaction paradigm: touch. With the introduction of touch-enabled Windows 8 machines, and now with the release of the awesome touch-enabled Chromebook Pixel, touch is now becoming part of the expected desktop experience. One of the biggest challenges is building experiences that work not only on touch devices and mouse devices, but also on these devices where the user will use both input methods - sometimes simultaneously!&lt;/p&gt;
&lt;p&gt;This article will help you understand how touch capabilities are built into the browser, how you can integrate this new interface mechanism into your existing apps and how touch can play nicely with mouse input.&lt;/p&gt;
&lt;h2 id=&quot;the-state-of-touch-in-the-web-platform&quot;&gt;The State of Touch in the Web Platform &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/mobile-touchandmouse/#the-state-of-touch-in-the-web-platform&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The iPhone was the first popular platform to have dedicated touch APIs built in to the web browser.  Several other browser vendors have created similar API interfaces built to be compatible with the iOS implementation, which is now described by the &lt;a href=&quot;http://www.w3.org/TR/touch-events/&quot; rel=&quot;noopener&quot;&gt;&amp;quot;Touch Events version 1&amp;quot; specification&lt;/a&gt;. Touch events are supported by Chrome and Firefox on desktop, and by Safari on iOS and Chrome and the Android browser on Android, as well as other mobile browsers like the Blackberry browser.&lt;/p&gt;
&lt;p&gt;My colleague Boris Smus wrote a great &lt;a href=&quot;http://www.html5rocks.com/en/mobile/touch/&quot; rel=&quot;noopener&quot;&gt;HTML5Rocks tutorial on Touch events&lt;/a&gt; that is still a good way to get started if you haven’t looked at Touch events before.  In fact, if you haven’t worked with touch events before, go read that article now, before you continue.  Go on, I’ll wait.&lt;/p&gt;
&lt;p&gt;All done?  Now that you have a basic grounding in touch events, the challenge with writing touch-enabled interactions is that the touch interactions can be quite a bit different from mouse (and mouse-emulating trackpad and trackball) events - and although touch interfaces typically try to emulate mice, that emulation isn’t perfect or complete; you really need to work through both interaction styles, and may have to support each interface independently.&lt;/p&gt;
&lt;h2 id=&quot;most-importantly-the-user-may-have-touch-and-a-mouse&quot;&gt;Most Importantly: The User May Have Touch And a Mouse &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/mobile-touchandmouse/#most-importantly-the-user-may-have-touch-and-a-mouse&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many developers have built sites that statically detect whether an environment supports touch events, and then make the assumption that they only need to support touch (and not mouse) events.  This is now a faulty assumption - instead, just because touch events are present does not mean the user is primarily using that touch input device.  Devices such as the Chromebook Pixel and some Windows 8 laptops now support BOTH Mouse and Touch input methods, and more will in the near future.  On these devices, it is quite natural for users to use both the mouse and the touch screen to interact with applications, so  &amp;quot;supports touch&amp;quot; is not the same as &amp;quot;doesn’t need mouse support.&amp;quot;  You can’t think of the problem as &amp;quot;I have to write two different interaction styles and switch between them,&amp;quot; you need to think through how both interactions will work together as well as independently.  On my Chromebook Pixel, I frequently use the trackpad, but I also reach up and touch the screen - on the same application or page, I do whatever feels most natural at the moment.  On the other hand, some touchscreen laptop users will rarely if ever use the touchscreen at all - so the presence of touch input shouldn’t disable or hinder mouse control.&lt;/p&gt;
&lt;p&gt;Unfortunately, it can be hard to know if a user’s browser environment supports touch input or not; ideally, a browser on a desktop machine would always indicate support for touch events so a touchscreen display could be attached at any time (e.g. if a touchscreen attached through a &lt;a href=&quot;http://en.wikipedia.org/wiki/KVM_switch&quot; rel=&quot;noopener&quot;&gt;KVM&lt;/a&gt; becomes available).  For all these reasons, your applications shouldn’t attempt to switch between touch and mouse - just support both!&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; In IE10 on Windows 8, Microsoft introduced a new model called Pointer Events.  Pointer Events are a unification of Mouse Events and touch input, as well as other input methods such as pen input.  There is &lt;a href=&quot;http://www.w3.org/TR/2013/WD-pointerevents-20130219/&quot;&gt;work to standardize the Pointer Event model at the W3C&lt;/a&gt;, and in the short term, there are libraries out there like &lt;a href=&quot;https://github.com/toolkitchen/PointerEvents&quot;&gt;PointerEvents&lt;/a&gt; and &lt;a href=&quot;http://blogs.msdn.com/b/eternalcoding/archive/2013/01/16/hand-js-a-polyfill-for-supporting-pointer-events-on-every-browser.aspx&quot;&gt;Hand.js&lt;/a&gt; that you can use to prototype how Pointer Events could work in your code to remove some of the need to independently support mouse and touch.  For really great touch and mouse interaction, you may need to customize your user experience for mouse and touch separately, but unified event handling can make this easier in many scenarios.  However, there are significant challenges with this model - namely, it requires supporting redundant input models, and it’s not broadly supported yet - and it will take some time to settle down into a solid, cross-browser standard.  In the meantime, the best advice is to support both mouse and touch interaction models.  There are a lot of challenges with simultaneously supporting touch and mouse events, so this article explains those challenges and the strategies to overcome them.  Additionally, some of this advice is just general &amp;quot;implementing touch&amp;quot; advice, so it may be redundant if you are already used to implementing touch in a mobile context. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;supporting-mouse-and-touch-together&quot;&gt;Supporting Mouse and Touch Together &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/mobile-touchandmouse/#supporting-mouse-and-touch-together&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;#1-clicking-and-tapping-the-natural-order-of-things&quot;&gt;#1 - Clicking and Tapping - the &amp;quot;Natural&amp;quot; Order of Things &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/mobile-touchandmouse/##1-clicking-and-tapping-the-natural-order-of-things&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first problem is that touch interfaces typically try to emulate mouse clicks - obviously, since touch interfaces need to work on applications that have only interacted with mouse events before!  You can use this as a shortcut - because &amp;quot;click&amp;quot; events will continue to be fired, whether the user clicked with a mouse or tapped their finger on the screen.  However, there are a couple of problems with this shortcut.&lt;/p&gt;
&lt;p&gt;First, you have to be careful when designing more advanced touch interactions: when the user uses a mouse it will respond via a click event, but when the user touches the screen both touch and click events will occur.  For a single click the order of events is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;touchstart&lt;/li&gt;
&lt;li&gt;touchmove&lt;/li&gt;
&lt;li&gt;touchend&lt;/li&gt;
&lt;li&gt;mouseover&lt;/li&gt;
&lt;li&gt;mousemove&lt;/li&gt;
&lt;li&gt;mousedown&lt;/li&gt;
&lt;li&gt;mouseup&lt;/li&gt;
&lt;li&gt;click&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This, of course, means that if you are processing touch events like touchstart, you need to make sure that you don’t process the corresponding mousedown and/or click event as well.  If you can cancel the touch events (call preventDefault() inside the event handler), then no mouse events will get generated for touch.  One of the most important rules of touch handlers is:&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-tertiary-box-bg color-tertiary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; role=&quot;img&quot; aria-label=&quot;Lightbulb&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path d=&quot;M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6A4.997 4.997 0 017 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Important&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Use preventDefault() inside touch event handlers, so the default mouse-emulation handling doesn’t occur. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;However, this also prevents other default browser behavior (like scrolling) - although usually you’re handling the touch event entirely in your handler, and you will WANT to disable the default actions.  In general, you’ll either want to handle and cancel all touch events, or avoid having a handler for that event.&lt;/p&gt;
&lt;p&gt;Secondly, when a user taps on an element in a web page on a mobile device, pages that haven’t been designed for mobile interaction have a delay of at least 300 milliseconds between the touchstart event and the processing of mouse events (mousedown). It could be done using Chrome, you can turn on &lt;a href=&quot;https://developers.google.com/chrome-developer-tools/docs/mobile-emulation#emulate-touch-events&quot; rel=&quot;noopener&quot;&gt;&amp;quot;Emulate touch events&amp;quot;&lt;/a&gt; in Chrome Developer Tools to help you test touch interfaces on a non-touch system!&lt;/p&gt;
&lt;p&gt;This delay is to allow the browser time to determine if the user is performing another gesture - in particular, double-tap zooming.  Obviously, this can be problematic in cases where you want to have instantaneous response to a finger touch.  There is &lt;a href=&quot;https://code.google.com/p/chromium/issues/detail?id=169642&quot; rel=&quot;noopener&quot;&gt;ongoing work&lt;/a&gt; to try to limit the scenarios in which this delay occurs automatically.&lt;/p&gt;
&lt;div class=&quot;table-wrapper scrollbar&quot;&gt;
  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;&lt;/th&gt;
        &lt;th&gt;Chrome for Android&lt;/th&gt;
        &lt;th&gt;Android Browser&lt;/th&gt;
        &lt;th&gt;Opera Mobile for Android)&lt;/th&gt;
        &lt;th&gt;Firefox for Android&lt;/th&gt;
        &lt;th&gt;Safari iOS&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;Non-scalable viewport&lt;/td&gt;
        &lt;td&gt;No delay&lt;/td&gt;
        &lt;td&gt;300ms&lt;/td&gt;
        &lt;td&gt;300ms&lt;/td&gt;
        &lt;td&gt;No delay&lt;/td&gt;
        &lt;td&gt;300ms&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;No Viewport&lt;/td&gt;
        &lt;td&gt;300ms&lt;/td&gt;
        &lt;td&gt;300ms&lt;/td&gt;
        &lt;td&gt;300ms&lt;/td&gt;
        &lt;td&gt;300ms&lt;/td&gt;
        &lt;td&gt;300ms&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;The first and easiest way to avoid this delay is to &amp;quot;tell&amp;quot; the mobile browser that your page is not going to need zooming - which can be done using a fixed viewport, e.g. by inserting into your page:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width,user-scalable=no&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This isn’t always appropriate, of course - this disables pinch-zooming, which may be required for accessibility reasons, so use it sparingly if at all (if you do disable user scaling, you may want to provide some other way to increase text readability in your application).  Also, for Chrome on desktop class devices that support touch, and other browsers on mobile platforms when the page has viewports that are not scalable, &lt;a href=&quot;http://paulkinlan.github.com/touch-patterns/touch-event-order-no-viewport&quot; rel=&quot;noopener&quot;&gt;this delay does not apply.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;#2-mousemove-events-arent-fired-by-touch&quot;&gt;#2: Mousemove Events Aren’t Fired by Touch &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/mobile-touchandmouse/##2-mousemove-events-arent-fired-by-touch&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It’s important to note at this point that the emulation of mouse events in a touch interface does not typically extend to emulating mousemove events - so if you build a beautiful mouse-driven control that uses mousemove events, it probably won’t work with a touch device unless you specifically add touchmove handlers too.&lt;/p&gt;
&lt;p&gt;Browsers typically automatically implement the appropriate interaction for touch interactions on the HTML controls - so, for example, HTML5 Range controls will just work when you use touch interactions.  However, if you’ve implemented your own controls, they will likely not work on click-and-drag type interactions; in fact, some commonly used libraries (like jQueryUI) do not yet natively support touch interactions in this way (although for jQueryUI, there are several monkey-patch fixes to this issue).  This was one of the first problems I ran into when upgrading my  Web Audio Playground application to work with touch - the sliders were jQueryUI-based, so they did not work with click-and-drag interactions.  I changed over to HTML5 Range controls, and they worked.  Alternately, of course, I could have simply added touchmove handlers to update the sliders, but there’s one problem with that…&lt;/p&gt;
&lt;h3 id=&quot;#3-touchmove-and-mousemove-arent-the-same-thing&quot;&gt;#3: Touchmove and MouseMove Aren’t the Same Thing &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/mobile-touchandmouse/##3-touchmove-and-mousemove-arent-the-same-thing&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A pitfall I&#39;ve seen a few developers fall into is having touchmove and mousemove handlers call into the same codepaths.  The behavior of these events is very close, but subtly different - in particular, &lt;strong&gt;&lt;strong&gt;touch events always target the element where that touch STARTED, while mouse events target the element currently under the mouse cursor.&lt;/strong&gt;&lt;/strong&gt;   This is why we have mouseover and mouseout events, but there are no corresponding touchover and touchout events - only touchend.&lt;/p&gt;
&lt;p&gt;The most common way this can bite you is if you happen to remove (or relocate) the element that the user started touching. For example, imagine an image carousel with a touch handler on the entire carousel to support custom scrolling behavior. As available images change, you remove some &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; elements and add others. If the user happens to start touching on one of those images and then you remove it, your handler (which is on an ancestor of the img element) will just stop receiving touch events (because they’re being dispatched to a target that’s no longer in the tree) - it&#39;ll look like the user is holding their finger in one place even though they may have moved and eventually removed it.&lt;/p&gt;
&lt;p&gt;You can of course avoid this problem by avoiding removing elements that have (or have ancestors that have) touch handlers while a touch is active. Alternately, the best guidance is rather than register static touchend/touchmove handlers, wait until you get a touchstart event and then add touchmove/touchend/touchcancel handlers to the &lt;strong&gt;&lt;strong&gt;target&lt;/strong&gt;&lt;/strong&gt; of the touchstart event (and remove them on end/cancel). This way you&#39;ll continue to receive events for the touch even if the target element is moved/removed. You can play with this a little &lt;a href=&quot;http://www.rbyers.net/eventTest.html&quot; rel=&quot;noopener&quot;&gt;here&lt;/a&gt; - touch the red box and while holding hit escape to remove it from the DOM.&lt;/p&gt;
&lt;h3 id=&quot;#4-touch-and-hover&quot;&gt;#4: Touch and :Hover &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/mobile-touchandmouse/##4-touch-and-hover&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The mouse pointer metaphor separated cursor position from actively selecting, and this allowed developers to use hover states to hide and show information that might be pertinent to the users.  However, most touch interfaces right now do not detect a finger &amp;quot;hovering&amp;quot; over a target - so providing semantically important information (e.g. providing &amp;quot;what is this control?&amp;quot; popup) based on hovering is a no-no, unless you also give a touch-friendly way to access this information.  You need to be careful about how you use hovering to relay information to users.&lt;/p&gt;
&lt;p&gt;Interestingly enough, though, the CSS :hover pseudoclass CAN be triggered by touch interfaces in some cases - tapping an element makes it :active while the finger is down, and it also acquires the :hover state.  (With Internet Explorer, the :hover is only in effect while the user’s finger is down - other browsers keep the :hover in effect until the next tap or mouse move.) This is a good approach to making pop-out menus work on touch interfaces - a side effect of making an element active is that the :hover state is also applied.  For example:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;img ~ .content&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;img:hover ~ .content&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/awesome.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;This is an awesome picture of me&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Once another element is tapped the element is no longer active, and the hover state disappears, just as if the user was using a mouse pointer and moved it off the element.  You may wish to wrap the content in an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; element in order to make it a tabstop as well - that way the user can toggle the extra information on a mouse hover or click, a touch tap, or a keypress, with no JavaScript required.  I was pleasantly surprised as I began work to make my &lt;a href=&quot;http://webaudioplayground.appspot.com/&quot; rel=&quot;noopener&quot;&gt;Web Audio Playground&lt;/a&gt; to work well with touch interfaces that my pop-out menus already worked well on touch, because I’d used this kind of structure!&lt;/p&gt;
&lt;p&gt;The above method works well for mouse pointer based interfaces, as well as for touch interfaces. This is in contrast to using &amp;quot;title&amp;quot; attributes on hover, which will NOT show up when the element is activated:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/awesome.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;this doesn&lt;span class=&quot;token punctuation&quot;&gt;&#39;&lt;/span&gt;t show up in touch&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Additional hover-like semantics you may wish to consider:  - Implement &amp;quot;touch and hold&amp;quot; as a &amp;quot;secondary click&amp;quot;.  On many devices - mobile and desktop alike - a touch-and-hold is already used to implement a context menu, so you shouldn’t use your own timer - listen for the oncontextmenu event, and be sure to cancel the default behavior. - Make the UI take two single touch events to complete the click - the first click will show the hover information, the second will complete the action. - If you are implementing hover effects as a way to provide help information - &amp;quot;what does this control do&amp;quot; sort of information - you may wish to just provide a &amp;quot;help mode&amp;quot; that toggles on this behavior. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;#5-touch-vs-mouse-precision&quot;&gt;#5: Touch vs. Mouse Precision &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/mobile-touchandmouse/##5-touch-vs-mouse-precision&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While mice have a conceptual disassociation from reality, it turns out that they are extremely accurate, as the underlying operating system generally tracks exact pixel precision for the cursor.  Mobile developers on the other hand have learned that finger touches on a touch screen are not as accurate, mostly because of the size of the surface area of the finger when in contact with the screen (and partly because your fingers obstruct the screen).&lt;/p&gt;
&lt;p&gt;Many individuals and companies have done extensive user research on how to design applications and sites that are accommodating of finger based interaction, and many books have been written on the topic.  The basic advice is to increase the size of the touch targets by increasing the padding, and reduce the likelihood of incorrect taps by increasing the margin between elements.  (Margins are not included in the hit detection handling of touch and click events, while padding is.)  One of the primary fixes I had to make to the Web Audio Playground was to increase the sizes of the connection points so they were more easily touched accurately.&lt;/p&gt;
&lt;p&gt;Many browser vendors who are handling touch based interfaces have also introduced logic into the browser to help target the correct element when a user touches the screen and reduce the likelihood of incorrect clicks - although this usually only corrects click events, not moves (although Internet Explorer appears to modify mousedown/mousemove/mouseup events as well).&lt;/p&gt;
&lt;h3 id=&quot;#6-keep-touch-handlers-contained,-or-theyll-jank-your-scroll&quot;&gt;#6: Keep Touch Handlers Contained, or They’ll Jank Your Scroll &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/mobile-touchandmouse/##6-keep-touch-handlers-contained,-or-theyll-jank-your-scroll&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It’s also important to keep touch handlers confined only to the elements where you need them; touch elements can be very high-bandwidth, so it’s important to avoid touch handlers on scrolling elements (as your processing may interfere with browser optimizations for fast jank-free touch scrolling - modern browsers try to scroll on a GPU thread, but this is impossible if they have to check with javascript first to see if each touch event is going to be handled by the app).  You can check out &lt;a href=&quot;http://www.rbyers.net/janky-touch-scroll.html&quot; rel=&quot;noopener&quot;&gt;an example&lt;/a&gt; of this behavior.&lt;/p&gt;
&lt;p&gt;One piece of guidance to follow to avoid this problem is to make sure that if you are only handling touch events in a small portion of your UI, you only attach touch handlers there (not, e.g., on the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; of the page); in short, limit the scope of your touch handlers as much as possible.&lt;/p&gt;
&lt;h3 id=&quot;#7-multi-touch&quot;&gt;#7: Multi-touch &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/mobile-touchandmouse/##7-multi-touch&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The final interesting challenge is that although we’ve been referring to it as &amp;quot;Touch&amp;quot; user interface, nearly universally the support is actually for Multi-touch - that is, the APIs provide more than one touch input at a time.  As you begin to support touch in your applications, you should consider how multiple touches might affect your application.&lt;/p&gt;
&lt;p&gt;If you have been building apps primarily driven by mouse, then you are used to building with at most one cursor point - systems don’t typically support multiple mice cursors.  For many applications, you will be just mapping touch events to a single cursor interface, but most of the hardware that we have seen for desktop touch input can handle at least 2 simultaneous inputs, and most new hardware appears to support at least 5 simultaneous inputs.  For developing an &lt;a href=&quot;http://webaudiodemos.appspot.com/midi-synth/index.html&quot; rel=&quot;noopener&quot;&gt;onscreen piano keyboard&lt;/a&gt;, of course, you would want to be able to support multiple simultaneous touch inputs.&lt;/p&gt;
&lt;p&gt;The currently implemented W3C Touch APIs have no API to determine how many touch points the hardware supports, so you’ll have to use your best estimation for how many touch points your users will want - or, of course, pay attention to how many touch points you see in practice and adapt.  For example, in a piano application, if you never see more than two touch points you may want to add some &amp;quot;chords&amp;quot; UI.  The PointerEvents API  does have an API to determine the capabilities of the device.&lt;/p&gt;
&lt;h2 id=&quot;touching-up&quot;&gt;Touching Up &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/mobile-touchandmouse/#touching-up&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hopefully this article has given you some guidance on common challenges in implementing touch alongside mouse interactions.  More important than any other advice, of course, is that you need to test your app on mobile, tablet, and combined mouse-and-touch desktop environments.  If you don’t have touch+mouse hardware, use Chrome’s &amp;quot;&lt;a href=&quot;https://developers.google.com/chrome-developer-tools/docs/mobile-emulation#emulate-touch-events&quot; rel=&quot;noopener&quot;&gt;Emulate touch events&lt;/a&gt;&amp;quot; to help you test the different scenarios.&lt;/p&gt;
&lt;p&gt;It’s not only possible, but relatively easy following these pieces of guidance, to build engaging interactive experiences that work well with touch input, mouse input, and even both styles of interaction at the same time.&lt;/p&gt;
</content>
    <author>
      <name>Chris Wilson</name>
    </author><author>
      <name>Paul Kinlan</name>
    </author>
  </entry>
  
  <entry>
    <title>A tale of two clocks</title>
    <link href="https://web.dev/audio-scheduling/"/>
    <updated>2013-01-09T00:00:00Z</updated>
    <id>https://web.dev/audio-scheduling/</id>
    <content type="html" mode="escaped">&lt;h2 id=&quot;introduction&quot;&gt;Introduction &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/audio-scheduling/#introduction&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the biggest challenges in building great audio and music software using the web platform is managing time.  Not as in “time to write code”, but as in clock time - one of the least well-understood topics about Web Audio is how to properly work with the audio clock. The Web Audio AudioContext object has a currentTime property that exposes this audio clock.&lt;/p&gt;
&lt;p&gt;Particularly for musical applications of web audio - not just writing sequencers and synthesizers, but any rhythmic use of audio events such as &lt;a href=&quot;http://chromium.googlecode.com/svn/trunk/samples/audio/shiny-drum-machine.html&quot; rel=&quot;noopener&quot;&gt;drum machines&lt;/a&gt;, &lt;a href=&quot;http://cappel-nord.de/webaudio/acid-defender/&quot; rel=&quot;noopener&quot;&gt;games&lt;/a&gt;, and &lt;a href=&quot;http://labs.dinahmoe.com/plink/&quot; rel=&quot;noopener&quot;&gt;other&lt;/a&gt; &lt;a href=&quot;http://chromium.googlecode.com/svn/trunk/samples/audio/granular.html&quot; rel=&quot;noopener&quot;&gt;applications&lt;/a&gt; - it’s very important to have consistent, precise timing of audio events; not just starting and stopping sounds, but also scheduling changes to the sound (like changing frequency or volume).  Sometimes it’s desirable to have slightly time-randomized events - for example, in the machine-gun demo in &lt;a href=&quot;http://www.html5rocks.com/en/tutorials/webaudio/games/&quot; rel=&quot;noopener&quot;&gt;Developing Game Audio with the Web Audio API&lt;/a&gt; - but usually, we want to have consistent and accurate timing for musical notes.&lt;/p&gt;
&lt;p&gt;We’ve already shown you how to schedule notes using the Web Audio noteOn and noteOff (now renamed start and stop) methods’ time parameter in &lt;a href=&quot;http://www.html5rocks.com/tutorials/webaudio/intro/&quot; rel=&quot;noopener&quot;&gt;Getting Started with Web Audio&lt;/a&gt; and also in &lt;a href=&quot;http://www.html5rocks.com/tutorials/webaudio/games/&quot; rel=&quot;noopener&quot;&gt;Developing Game Audio with the Web Audio API&lt;/a&gt;; however, we haven’t deeply explored more complex scenarios, such as playing long musical sequences or rhythms.  To dive into that, first we need a little background on clocks.&lt;/p&gt;
&lt;h2 id=&quot;the-best-of-times-the-web-audio-clock&quot;&gt;The Best of Times - the Web Audio Clock &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/audio-scheduling/#the-best-of-times-the-web-audio-clock&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Web Audio API exposes access to the audio subsystem’s hardware clock.  This clock is exposed on the AudioContext object through its .currentTime property, as a floating-point number of seconds since the AudioContext was created.  This enables this clock (hereafter called the “audio clock”) to be very high-precision;  it’s designed to be able to specify alignment at an individual sound sample level, even with a high sample rate.  Since there are around 15 decimal digits of precision in a “double”, even if the audio clock has been running for days, it should still have plenty of bits left over to point to a specific sample even at a high sample rate.&lt;/p&gt;
&lt;p&gt;The audio clock is used for scheduling parameters and audio events throughout the Web Audio API - for &lt;a href=&quot;https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#dfn-start&quot; rel=&quot;noopener&quot;&gt;start()&lt;/a&gt; and &lt;a href=&quot;https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#dfn-stop&quot; rel=&quot;noopener&quot;&gt;stop()&lt;/a&gt;, of course, but also for &lt;a href=&quot;https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#methodsandparams-AudioParam&quot; rel=&quot;noopener&quot;&gt;set*ValueAtTime() methods&lt;/a&gt; on AudioParams.  This lets us set up very precisely-timed audio events in advance.  In fact, it’s tempting to just set up everything in Web Audio as start/stop times - however, in practice there’s a problem with that.&lt;/p&gt;
&lt;p&gt;For example, look at this reduced code snippet from our Web Audio Intro, which sets up two bars of an eighth note hi-hat pattern:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; bar &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; bar &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; bar&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; time &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; startTime &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; bar &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; eighthNoteTime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Play the hi-hat every eighth note.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;playSound&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hihat&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; time &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; eighthNoteTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This code will work great.  However, if you want to change the tempo in the middle of those two bars - or stop playing before the two bars are up - you’re out of luck. (I’ve seen developers do things like insert a gain node between their pre-scheduled AudioBufferSourceNodes and the output, just so they can mute their own sounds!)&lt;/p&gt;
&lt;p&gt;In short, because you will need the flexibility to change tempo or parameters like frequency or gain (or stop scheduling altogether), you don’t want to push too many audio events into the queue - or, more accurately, you don’t want to look ahead too far in time, because you may want to change that scheduling entirely.&lt;/p&gt;
&lt;h2 id=&quot;the-worst-of-times-the-javascript-clock&quot;&gt;The Worst of Times - the JavaScript Clock &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/audio-scheduling/#the-worst-of-times-the-javascript-clock&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We also have our much-beloved and much-maligned JavaScript clock, represented by Date.now() and setTimeout().  The good side of the JavaScript clock is that it has a couple of very useful call-me-back-later window.setTimeout() and window.setInterval() methods, which let us have the system call our code back at specific times.&lt;/p&gt;
&lt;p&gt;The bad side of the JavaScript clock is that it is not very precise.  For starters, Date.now() returns a value in milliseconds - an integer number of milliseconds - so the best precision you could hope for is one millisecond.  This isn’t incredibly bad in some musical contexts - if your note started a millisecond early or late, you might not even notice - but even at a relatively low audio hardware rate of 44.1kHz, it’s about 44.1 times too slow to use as an audio scheduling clock.  Remember that dropping any samples at all can cause audio glitching - so if we’re chaining samples together, we may need them to be precisely sequential.&lt;/p&gt;
&lt;p&gt;The up-and-coming &lt;a href=&quot;http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/HighResolutionTime/Overview.html&quot; rel=&quot;noopener&quot;&gt;High Resolution Time specification&lt;/a&gt; actually does give us a much better precision current time through window.performance.now(); it’s even implemented (albeit prefixed) in many current browsers.  That can help in some situations, although it’s not really relevant to the worst part of the JavaScript timing APIs.&lt;/p&gt;
&lt;p&gt;The worst part of the JavaScript timing APIs are that although Date.now()’s millisecond precision doesn’t sound too bad to live with, the actual callback of timer events in JavaScript (through window.setTimeout() or window.setInterval) can easily be skewed by tens of milliseconds or more by layout, rendering, garbage collection, and XMLHTTPRequest and other callbacks - in short, by any number of things happening on the main execution thread.  Remember how I mentioned “audio events” that we could schedule using the Web Audio API?  Well, those are all getting processed on a separate thread - so even if the main thread is temporarily stalled doing a complex layout or other long task, the audio will still happen at exactly the times they were told to happen - in fact, even if you’re stopped at a breakpoint in the debugger, the audio thread will continue to play scheduled events!&lt;/p&gt;
&lt;h2 id=&quot;using-javascript-settimeout-in-audio-apps&quot;&gt;Using JavaScript setTimeout() in Audio Apps &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/audio-scheduling/#using-javascript-settimeout-in-audio-apps&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since the main thread can easily get stalled for multiple milliseconds at a time, it is a bad idea to use JavaScript’s setTimeout to directly start playing audio events, because at best your notes will fire within a millisecond or so of when they really should, and at worst they will be delayed for even longer.  Worst of all, for what should be rhythmic sequences, they won’t fire at precise intervals as the timing will be sensitive to other things happening on the main JavaScript thread.&lt;/p&gt;
&lt;p&gt;To demonstrate this, I wrote a sample “bad” metronome application  - that is, one that uses setTimeout directly to schedule notes - and also does a lot of layout.  Open this application, click “play”, and then resize the window quickly while it’s playing; you’ll notice that the timing is noticeably jittery (you can hear the rhythm doesn&#39;t stay consistent).  “But this is contrived!” you say?  Well, of course - but that doesn’t mean it doesn’t happen in the real world too.  Even relatively static user interface will have timing issues in setTimeout due to relayouts - for example, I noticed that resizing the window quickly will cause the timing on the otherwise excellent &lt;a href=&quot;http://jeremywentworth.com/webkitSynth/&quot; rel=&quot;noopener&quot;&gt;WebkitSynth&lt;/a&gt; to stutter noticeably.  Now picture what will happen when you’re trying to smooth-scroll a full musical score along with your audio, and you can easily imagine how this would affect complex music apps in the real world.&lt;/p&gt;
&lt;p&gt;One of the most frequently-asked questions I hear is “Why can’t I get callbacks from audio events?”  Although there may be uses for these types of callbacks, they wouldn’t solve the particular problem at hand - it’s important to understand that those events would be fired in the main JavaScript thread, so they would be subject to all the same potential delays as setTimeout; that is, they could be delayed for some unknown and variable number of milliseconds from the precise time they were scheduled before they were actually processed.&lt;/p&gt;
&lt;p&gt;So what can we do?  Well, the best way to handle timing is to set up a collaboration between JavaScript timers (setTimeout(), setInterval() or requestAnimationFrame() - more on that later) and the audio hardware scheduling.&lt;/p&gt;
&lt;h2 id=&quot;obtaining-rock-solid-timing-by-looking-ahead&quot;&gt;Obtaining Rock-Solid Timing By Looking Ahead &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/audio-scheduling/#obtaining-rock-solid-timing-by-looking-ahead&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let’s go back to that metronome demo - in fact, I wrote the first version of this simple metronome demo correctly to demonstrate this collaborative scheduling technique.  (&lt;a href=&quot;http://github.com/cwilso/metronome/&quot; rel=&quot;noopener&quot;&gt;The code is also available on Github&lt;/a&gt;  This demo plays beep sounds (generated by an Oscillator) with high precision on every sixteenth, eighth, or quarter note, altering the pitch depending on the beat.  It also lets you change the tempo and note interval while it’s playing, or stop the playback at any time - which is a key feature for any real-world rhythmic sequencer.  It would be pretty easy to add code to change the sounds this metronome uses on the fly as well.&lt;/p&gt;
&lt;p&gt;The way that it manages to allow temp control while maintaining rock-solid timing is a collaboration: a setTimeout timer that fires once every so often, and sets up Web Audio scheduling in the future for individual notes.  The setTimeout timer basically just checks to see if any notes are going to need to be scheduled “soon” based on the current tempo, and then schedules them, like so:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;setTimeout() and audio event interactio.&quot; decoding=&quot;async&quot; height=&quot;545&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/pu23mak40dM0zYG3BkF9.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
  setTimeout() and audio event interaction.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In practice, setTimeout() calls may get delayed, so the timing of the scheduling calls may jitter (and skew, depending on how you use setTimeout) over time - although the events in this example fire approximately 50ms apart, they’re frequently slightly more than that (and sometimes much more).  However, during each call, we schedule Web Audio events not only for any notes that need to be played now (e.g. the very first note), but also any notes that need to be played between now and the next interval.&lt;/p&gt;
&lt;p&gt;In fact, we don’t want to just look ahead by precisely the interval between setTimeout() calls - we also need some scheduling overlap between this timer call and the next, in order to accommodate the worst case main thread behavior - that is, the worst case of garbage collection, layout, rendering or other code happening on the main thread delaying our next timer call.  We also need to account for the audio block-scheduling time - that is, how much audio the operating system keeps in its processing buffer - which varies across operating systems and hardware, from low single digits of milliseconds to around 50ms.  Each setTimeout() call shown above has a blue interval that shows the entire range of times during which it will attempt to schedule events; for example, the fourth web audio event scheduled in the diagram above might have been played “late” if we’d waited to play it until the next setTimeout call happened, if that setTimeout call was just a few milliseconds later.  In real life, the jitter in these times can be even more extreme than that, and this overlap becomes even more important as your app becomes more complex.&lt;/p&gt;
&lt;p&gt;The overall lookahead latency affects how tight the tempo control (and other real-time controls) can be; the interval between scheduling calls is a tradeoff between the minimum latency and how often your code impacts the processor.  How much the lookahead overlaps with the next interval’s start time is determines how resilient your app will be across different machines, and as it becomes more complex (and layout and garbage collection may take longer).  In general, to be resilient to slower machines and operating systems, it’s best to have a large overall lookahead and a reasonably short interval.  You can adjust to have shorter overlaps and longer intervals, in order to process fewer callbacks, but at some point, you might start hearing that a large latency causes tempo changes, etc., to not take effect immediately; conversely, if you lessened the lookahead too much, you might start hearing some jittering (as a scheduling call might have to “make up” events that should have happened in the past).&lt;/p&gt;
&lt;p&gt;The following timing diagram shows what the metronome demo code actually does: it has a setTimeout interval of 25ms, but a much more resilient overlap: each call will schedule for the next 100ms.  The downside of this long lookahead is that tempo changes, etc., will take a tenth of a second to take effect; however, we are much more resilient to interruptions:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Scheduling with long overlaps.&quot; decoding=&quot;async&quot; height=&quot;486&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/PdnVZLRqwpDqMAHRFDGb.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
  scheduling with long overlaps
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In fact, you can tell in this example we had a setTimeout interruption in the middle - we should have had a setTimeout callback at approximately 270ms, but it was delayed for some reason until approximately 320ms - 50ms later than it should have been!  However, the large lookahead latency kept the timing going with no problem, and we didn’t miss a beat, even though we increased the tempo just before that to playing sixteenth notes at 240bpm (beyond even hardcore drum &amp;amp; bass tempos!)&lt;/p&gt;
&lt;p&gt;It’s also possible that each scheduler call might end up scheduling multiple notes - let’s take a look at what happens if we use a longer scheduling interval (250ms lookahead, spaced 200ms apart), and a tempo increase in the middle:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;setTimeout() with long lookahead and long intervals.&quot; decoding=&quot;async&quot; height=&quot;247&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/nWBTmc8SLQadveHqIt8D.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
  setTimeout() with long lookahead and long intervals
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This case demonstrates that each setTimeout() call may end up scheduling multiple audio events - in fact, this metronome is a simple one-note-at-a-time application, but you can easily see how this approach works for a drum machine (where there are frequently multiple simultaneous notes) or a sequencer (that may frequently have non-regular intervals between notes).&lt;/p&gt;
&lt;p&gt;In practice, you’ll want to tune your scheduling interval and the lookahead to see how affected it is by layout, garbage collection and other things going on in the main JavaScript execution thread, and to tune the granularity of control over tempo, etc.  If you have a very complex layout that happens frequently, for example, you’ll probably want to make the lookahead larger.  The main point is that we want the amount of “scheduling ahead” that we’re doing to be large enough to avoid any delays, but not so large as to be create noticeable delay when tweaking the tempo control.  Even the case above has a very small overlap, so it won’t be very resilient on a slow machine with a complex web application.  A good place to start is probably 100ms of “lookahead” time, with intervals set to 25ms.  This may still have problems in complex applications on machines with a lot of audio system latency, in which case you should up the lookahead time; or, if you need tighter control with the loss of some resilience, use a shorter lookahead.&lt;/p&gt;
&lt;p&gt;The core code of the scheduling process is in the scheduler() function -&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nextNoteTime &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; audioContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;currentTime &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; scheduleAheadTime &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;scheduleNote&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; current16thNote&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nextNoteTime &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;nextNote&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This function just gets the current audio hardware time, and compares it against the time for the next note in the sequence - most of the time* in this precise scenario this will do nothing (as there are no metronome “notes” waiting to be scheduled, but when it succeeds it will schedule that note using the Web Audio API, and advance to the next note.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; The scheduler is called every 25ms.  At a standard tempo of 120 quarter-note beats per minute - in our case, playing eight sixteenth notes a second - a note will come up for scheduling every 125ms.  So, roughly 60% of the scheduling calls in this case will find no new notes to be scheduled.  Although you’d have to hit a tempo of 300 quarter-note beats per minute before our simple sixteenth-note pattern would start scheduling multiple notes in a single scheduler() pass, the “while” clause is important once you start supporting more complex rhythms - 32nd or shorter notes, flams, arbitrary sequences, etc. - and of course the first call, with a long lookahead and a fast tempo, will probably buffer up multiple notes. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The scheduleNote() function is responsible for actually scheduling the next Web Audio “note” to be played.  In this case, I used oscillators to make beeping sounds at different frequencies; you could just as easily create AudioBufferSource nodes and set their buffers to drum sounds, or any other sounds you wish.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;currentNoteStartTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// create an oscillator&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; osc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; audioContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createOscillator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;osc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; audioContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;destination &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;beatNumber &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;         &lt;span class=&quot;token comment&quot;&gt;// beat 0 == low pitch&lt;/span&gt;&lt;br /&gt;  osc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frequency&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;220.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;beatNumber &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;          &lt;span class=&quot;token comment&quot;&gt;// quarter notes = medium pitch&lt;/span&gt;&lt;br /&gt;  osc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frequency&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;440.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;                              &lt;span class=&quot;token comment&quot;&gt;// other 16th notes = high pitch&lt;/span&gt;&lt;br /&gt;  osc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frequency&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;880.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;osc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; time &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;osc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; time &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; noteLength &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Once those oscillators are scheduled and connected, this code can forget about them entirely; they will start, then stop, then get garbage-collected automatically.&lt;/p&gt;
&lt;p&gt;The nextNote() method is responsible for advancing to the next sixteenth note - that is, setting the nextNoteTime and current16thNote variables to the next note:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;nextNote&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Advance current note and time by a 16th note...&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; secondsPerBeat &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60.0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; tempo&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;	&lt;span class=&quot;token comment&quot;&gt;// picks up the CURRENT tempo value!&lt;/span&gt;&lt;br /&gt;  nextNoteTime &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.25&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; secondsPerBeat&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;	&lt;span class=&quot;token comment&quot;&gt;// Add 1/4 of quarter-note beat length to time&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  current16thNote&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;	&lt;span class=&quot;token comment&quot;&gt;// Advance the beat number, wrap to zero&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;current16thNote &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    current16thNote &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This is pretty straightforward - although it’s important to understand that in this scheduling example, I’m not keeping track of “sequence time” - that is, time since the beginning of starting the metronome.  All we have to do is remember when we played the last note, and figure out when the next note is scheduled to play.  That way, we can change the tempo (or stop playing) very easily.&lt;/p&gt;
&lt;p&gt;This scheduling technique is used by a number of other audio applications on the web - for example, the  &lt;a href=&quot;http://chromium.googlecode.com/svn/trunk/samples/audio/shiny-drum-machine.html&quot; rel=&quot;noopener&quot;&gt;Web Audio Drum Machine&lt;/a&gt;, the very fun &lt;a href=&quot;http://cappel-nord.de/webaudio/acid-defender/&quot; rel=&quot;noopener&quot;&gt;Acid Defender game&lt;/a&gt;, and even more in-depth audio examples like the &lt;a href=&quot;http://chromium.googlecode.com/svn/trunk/samples/audio/granular.html&quot; rel=&quot;noopener&quot;&gt;Granular Effects demo&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;yet-another-timing-system&quot;&gt;Yet Another Timing System &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/audio-scheduling/#yet-another-timing-system&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now, as any good musician knows, what every audio application needs is more cowbell - er, more timers.  It’s worth mentioning that the right way to do visual display is making use of a THIRD timing system!&lt;/p&gt;
&lt;p&gt;Why, why, oh dear heavens why do we need another timing system?  Well, this one is synchronized to the visual display - that is, the graphics refresh rate - via the &lt;a href=&quot;http://www.html5rocks.com/en/tutorials/speed/rendering/&quot; rel=&quot;noopener&quot;&gt;requestAnimationFrame API&lt;/a&gt;.  For drawing boxes in our metronome example, this may not seem like a really a big deal, but as your graphics get more and more complex, it becomes more and more critical to be using requestAnimationFrame() to sync with the visual refresh rate - and it’s actually just as easy to use from the beginning as using setTimeout()!  With very complex synced graphics (e.g. precise display of dense musical notes as they play in a musical notation package), requestAnimationFrame() will give you the smoothest, most precise graphic and audio synchronization.&lt;/p&gt;
&lt;p&gt;We kept track of the beats in the queue in the scheduler:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;notesInQueue&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;note&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; beatNumber&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; time &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The interaction with our metronome’s current time can be found in the draw() method, which is called (using requestAnimationFrame) whenever the graphics system is ready for an update:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; currentTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; audioContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;currentTime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;notesInQueue&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; notesInQueue&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;time &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; currentTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  currentNote &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; notesInQueue&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;note&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  notesInQueue&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;splice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;// remove note from queue&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Again, you’ll notice that we are checking the audio system’s clock - because that’s really the one we want to synchronize with, since it will actually play the notes - to see if we should be drawing a new box or not.  In fact, we’re not really using the requestAnimationFrame timestamps at all, since we’re using the audio system clock to figure out where we are in time.&lt;/p&gt;
&lt;p&gt;Of course, I could have just skipped using a setTimeout() callback altogether, and put my note scheduler into the requestAnimationFrame callback - then we’d be back down to two timers again.  That’s okay to do, too, but it’s important to understand that requestAnimationFrame is just a stand-in for setTimeout() in this case; you’ll still want the scheduling accuracy of Web Audio timing for the actual notes.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/audio-scheduling/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I hope this tutorial has been helpful in explaining clocks, timers and how to build great timing into web audio applications.  These same techniques can be extrapolated easily to build sequence players, drum machines, and more.  Until next time…&lt;/p&gt;
</content>
    <author>
      <name>Chris Wilson</name>
    </author>
  </entry>
  
  <entry>
    <title>Performance tips for JavaScript in V8</title>
    <link href="https://web.dev/speed-v8/"/>
    <updated>2012-10-11T00:00:00Z</updated>
    <id>https://web.dev/speed-v8/</id>
    <content type="html" mode="escaped">&lt;h2 id=&quot;introduction&quot;&gt;Introduction &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#introduction&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Daniel Clifford gave an &lt;a href=&quot;https://www.youtube.com/watch?v=UJPdhx5zTaw&quot; rel=&quot;noopener&quot;&gt;excellent talk at Google I/O&lt;/a&gt; on tips and tricks to improve JavaScript performance in V8.  Daniel encouraged us to &amp;quot;demand faster&amp;quot; - to carefully analyze performance differences between C++ and JavaScript, and write code mindfully of how JavaScript works.  A summary of the most important points of Daniel&#39;s talk are captured in this article, and we&#39;ll also keep this article updated as performance guidance changes.&lt;/p&gt;
&lt;h2 id=&quot;the-most-important-advice&quot;&gt;The Most Important Advice &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#the-most-important-advice&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It&#39;s important to put any performance advice into context.  Performance advice is addictive, and sometimes focusing on deep advice first can be quite distracting from the real issues. You need to take a holistic view of the performance of your web application - before focusing on these performance tip, you should probably analyze your code with tools like &lt;a href=&quot;https://developers.google.com/speed/pagespeed/&quot; rel=&quot;noopener&quot;&gt;PageSpeed&lt;/a&gt; and get your score up.  This will help you avoid premature optimization.&lt;/p&gt;
&lt;p&gt;The best basic advice for getting good performance in Web applications is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Be prepared before you have (or notice) a problem&lt;/li&gt;
&lt;li&gt;Then, identify and understand the crux of your problem&lt;/li&gt;
&lt;li&gt;Finally, fix what matters&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In order to accomplish these steps, it can be important to understand how V8 optimizes JS, so you can write code mindful of the JS runtime design.  It&#39;s also important to learn about the tools available and how they can help you.  Daniel goes into some more explanation of how to use the developer tools in his talk; this document just captures some of the most important points of the V8 engine design.&lt;/p&gt;
&lt;p&gt;So, on to the V8 tips!&lt;/p&gt;
&lt;h2 id=&quot;hidden-classes&quot;&gt;Hidden Classes &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#hidden-classes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;JavaScript has limited compile-time type information: types can be changed at runtime, so it&#39;s natural to expect that it is expensive to reason about JS types at compile time.  This might lead you to question how JavaScript performance could ever get anywhere close to C++.  However, V8 has hidden types created internally for objects at runtime; objects with the same hidden class can then use the same optimized generated code.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; p1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; p2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;33&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;44&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// At this point, p1 and p2 have a shared hidden class&lt;/span&gt;&lt;br /&gt;p2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;z &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// warning! p1 and p2 now have different hidden classes!```&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Until the object instance p2 has additional member &amp;quot;.z&amp;quot; added, p1 and p2 internally have the same hidden class - so V8 can generate a single version of optimized assembly for JavaScript code that manipulates either p1 or p2.  The more you can avoid causing the hidden classes to diverge, the better performance you&#39;ll obtain.&lt;/p&gt;
&lt;h3 id=&quot;therefore&quot;&gt;Therefore &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#therefore&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Initialize all object members in constructor functions (so the instances don&#39;t change type later)&lt;/li&gt;
&lt;li&gt;Always initialize object members in the same order&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;numbers&quot;&gt;Numbers &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#numbers&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;V8 uses tagging to represent values efficiently when types can change.  V8 infers from the values that you use what number type you are dealing with. Once V8 has made this inference, it uses tagging to represent values efficiently, because these types can change dynamically. However, there is sometimes a cost to changing these type tags, so it&#39;s best to use number types consistently, and in general it is most optimal to use 31-bit signed integers where appropriate.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// this is a 31-bit signed integer&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; j &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4.2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// this is a double-precision floating point number```&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;therefore-2&quot;&gt;Therefore &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#therefore-2&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Prefer numeric values that can be represented as 31-bit signed integers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;arrays&quot;&gt;Arrays &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#arrays&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In order to handle large and sparse arrays, there are two types of array storage internally:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fast Elements: linear storage for compact key sets&lt;/li&gt;
&lt;li&gt;Dictionary Elements: hash table storage otherwise&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&#39;s best not to cause the array storage to flip from one type to another.&lt;/p&gt;
&lt;h3 id=&quot;therefore-3&quot;&gt;Therefore &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#therefore-3&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Use contiguous keys starting at 0 for Arrays&lt;/li&gt;
&lt;li&gt;Don&#39;t pre-allocate large Arrays (e.g. &amp;gt; 64K elements) to their maximum size, instead grow as you go&lt;/li&gt;
&lt;li&gt;Don&#39;t delete elements in arrays, especially numeric arrays&lt;/li&gt;
&lt;li&gt;Don&#39;t load uninitialized or deleted elements:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;lt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; b&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|=&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Oh no!&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;//vs.&lt;/span&gt;&lt;br /&gt;a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;lt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; b&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|=&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// Much better! 2x faster.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Also, Arrays of doubles are faster - the array&#39;s hidden class tracks element types, and arrays containing only doubles are unboxed (which causes a hidden class change).However, careless manipulation of Arrays can cause extra work due to boxing and unboxing - e.g.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;77&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;// Allocates&lt;/span&gt;&lt;br /&gt;a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;88&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;// Allocates, converts&lt;/span&gt;&lt;br /&gt;a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Allocates, converts```&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;is less efficient than:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;77&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;88&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;because in the first example the individual assignments are performed one after another, and the assignment of &lt;code&gt;a[2]&lt;/code&gt; causes the Array to be converted to an Array of unboxed doubles, but then the assignment of &lt;code&gt;a[3]&lt;/code&gt; causes it to be re-converted back to an Array that can contain any values (Numbers or objects).  In the second case, the compiler knows the types of all of the elements in the literal, and the hidden class can be determined up front.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Initialize using array literals for small fixed-sized arrays&lt;/li&gt;
&lt;li&gt;Preallocate small arrays (&amp;lt;64k) to correct size before using them&lt;/li&gt;
&lt;li&gt;Don&#39;t store non-numeric values (objects) in numeric arrays&lt;/li&gt;
&lt;li&gt;Be careful not to cause re-conversion of small arrays if you do initialize without literals.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;javascript-compilation&quot;&gt;JavaScript Compilation &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#javascript-compilation&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Although JavaScript is a very dynamic language, and original implementations of it were interpreters, modern JavaScript runtime engines use compilation.  V8 (Chrome&#39;s JavaScript) has two different Just-In-Time (JIT) compilers, in fact:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &amp;quot;Full&amp;quot; compiler, which can generate good code for any JavaScript&lt;/li&gt;
&lt;li&gt;The Optimizing compiler, which produces great code for most JavaScript, but takes longer to compile.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-full-compiler&quot;&gt;The Full Compiler &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#the-full-compiler&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In V8, the Full compiler runs on all code, and starts executing code as soon as possible, quickly generating good but not great code.  This compiler assumes almost nothing about types at compilation time - it expects that types of variables can and will change at runtime.  The code generated by the Full compiler uses Inline Caches (ICs) to refine knowledge about types while program runs, improving efficiency on the fly.&lt;/p&gt;
&lt;p&gt;The goal of Inline Caches is to handle types efficiently, by caching type-dependent code for operations; when the code runs, it will validate type assumptions first, then use the inline cache to shortcut the operation.  However, this means that operations that accept multiple types will be less performant.&lt;/p&gt;
&lt;h3 id=&quot;therefore-4&quot;&gt;Therefore &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#therefore-4&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Monomorphic use of operations is preferred over polymorphic operations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Operations are monomorphic if the hidden classes of inputs are always the same - otherwise they are polymorphic, meaning some of the arguments can change type across different calls to the operation.  For example, the second add() call in this example causes polymorphism:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;      &lt;span class=&quot;token comment&quot;&gt;// + in add is monomorphic&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// + in add becomes polymorphic```&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;the-optimizing-compiler&quot;&gt;The Optimizing Compiler &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#the-optimizing-compiler&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In parallel with the full compiler, V8 re-compiles &amp;quot;hot&amp;quot; functions (that is, functions that are run many times) with an optimizing compiler.  This compiler uses type feedback to make the compiled code faster - in fact, it uses the types taken from ICs we just talked about!&lt;/p&gt;
&lt;p&gt;In the optimizing compiler, operations get speculatively inlined (directly placed where they are called).  This speeds execution (at the cost of memory footprint), but also enables other optimizations.  Monomorphic functions and constructors can be inlined entirely (that&#39;s another reason why monomorphism is a good idea in V8).&lt;/p&gt;
&lt;p&gt;You can log what gets optimized using the standalone &amp;quot;d8&amp;quot; version of the V8 engine:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;d8 --trace-opt primes.js&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;(this logs names of optimized functions to stdout.)&lt;/p&gt;
&lt;p&gt;Not all functions can be optimized, however - some features prevent the optimizing compiler from running on a given function (a &amp;quot;bail-out&amp;quot;).  In particular, the optimizing compiler currently bails out on functions with try {} catch {} blocks!&lt;/p&gt;
&lt;h3 id=&quot;therefore-5&quot;&gt;Therefore &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#therefore-5&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Put perf-sensitive code into a nested function if you have try {} catch {} blocks:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;perf_sensitive&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Do performance-sensitive work here&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;perf_sensitive&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Handle exceptions here&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This guidance will probably change in the future, as we enable try/catch blocks in the optimizing compiler. You can examine how the optimizing compiler is bailing out on functions by using the &amp;quot;--trace-opt&amp;quot; option with d8 as above, which gives you more information on which functions were bailed out:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;d8 --trace-opt primes.js&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;de-optimization&quot;&gt;De-optimization &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#de-optimization&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Finally, the optimization performed by this compiler is speculative - sometimes it doesn&#39;t work out, and we back off.  The process of &amp;quot;deoptimization&amp;quot; throws away optimized code, and resumes execution at the right place in &amp;quot;full&amp;quot; compiler code.  Reoptimization might be triggered again later, but for the short term, execution slows down.  In particular, causing changes in the hidden classes of variables after the functions have been optimized will cause this deoptimization to occur.&lt;/p&gt;
&lt;h3 id=&quot;therefore-6&quot;&gt;Therefore &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#therefore-6&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Avoid hidden class changes in functions after they are optimized&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can, as with other optimizations, get a log of functions that V8 had to deoptimize with a logging flag:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;d8 --trace-deopt primes.js&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;other-v8-tools&quot;&gt;Other V8 Tools &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#other-v8-tools&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By the way, you can also pass V8 tracing options to Chrome on startup:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/Applications/Google Chrome.app/Contents/MacOS/Google Chrome&quot;&lt;/span&gt; --js-flags&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;--trace-opt --trace-deopt&quot;&lt;/span&gt;```&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In addition to using the developer tools profiling, you can also use d8 to do profiling:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;% out/ia32.release/d8 primes.js --prof&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This uses the built-in sampling profiler, which takes a sample every millisecond and writes v8.log.&lt;/p&gt;
&lt;h2 id=&quot;in-summary&quot;&gt;In Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#in-summary&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It&#39;s important to indentify and understand how the V8 engine works with your code to prepare to build performant JavaScript.  Once more, the basic advice is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Be prepared before you have (or notice) a problem&lt;/li&gt;
&lt;li&gt;Then, identify and understand the crux of your problem&lt;/li&gt;
&lt;li&gt;Finally, fix what matters&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This means you should ensure the problem is in your JavaScript, by using other tools like PageSpeed first; possibly reducing to to pure JavaScript (no DOM) before collecting metrics, and then use those metrics to locate bottlenecks and eliminate the important ones.  Hopefully Daniel&#39;s talk (and this article) will help you understand better how V8 runs JavaScript - but be sure to focus on optimizing your own algorithms, too!&lt;/p&gt;
&lt;h2 id=&quot;references&quot;&gt;References &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/speed-v8/#references&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=UJPdhx5zTaw&quot; rel=&quot;noopener&quot;&gt;Daniel&#39;s talk on YouTube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://v8-io12.appspot.com/&quot; rel=&quot;noopener&quot;&gt;Daniel&#39;s slide deck&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://mrale.ph/blog/2011/12/18/v8-optimization-checklist.html&quot; rel=&quot;noopener&quot;&gt;I-want-to-optimize-my-JS-application-on-V8 checklist by Vyacheslav Egorov, V8 Engineer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Chris Wilson</name>
    </author>
  </entry>
</feed>
