{"id":269,"date":"2017-03-13T15:46:32","date_gmt":"2017-03-13T15:46:32","guid":{"rendered":"https:\/\/blog.mozilla.org\/webrtc\/?p=269"},"modified":"2018-08-01T19:24:14","modified_gmt":"2018-08-01T19:24:14","slug":"fiddle-of-the-week-await","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/","title":{"rendered":"Fiddle-of-the-week: await WebRTC in Firefox 52"},"content":{"rendered":"<p>This isn&#8217;t a post about a new WebRTC feature. Rather, we&#8217;ll explore the new <a href=\"https:\/\/developers.google.com\/web\/fundamentals\/getting-started\/primers\/async-functions\"><code>async<\/code>\/<code>await<\/code> JavaScript syntax<\/a> in the <a href=\"https:\/\/hacks.mozilla.org\/2017\/03\/firefox-52-introducing-web-assembly-css-grid-and-the-grid-inspector\/\">just-released Firefox 52<\/a> and Chrome! Two new keywords let us <a href=\"https:\/\/developers.google.com\/web\/fundamentals\/getting-started\/primers\/async-functions\">write asynchronous code the same way we&#8217;d write synchronous code<\/a>. WebRTC APIs, as you&#8217;re probably aware, are quite asynchronous. Luckily they support promises &#8211; a requirement to use this new syntax &#8211; and it just works! I&#8217;ve always found callbacks and even monadic promise-chains hard to follow, but now we can write short, yet meaningful code that gets stuff done.<!--more--><\/p>\n<p><em>&#8220;Big deal&#8221;<\/em> you say, <em>&#8220;maybe I&#8217;ll be able to use this in production in 2027!&#8221;<\/em> Well, it turns out you can use <a href=\"https:\/\/developers.google.com\/web\/fundamentals\/getting-started\/primers\/async-functions#workaround_-_generators\">Babel to transpile this down to code IE8 will understand<\/a>. But even if you&#8217;re not planning on doing that, I find learning how to write this way helps me reason about complicated WebRTC behaviors more easily. The code now matches how we talk about it, a boon to understanding and communication; it\u2019s my new whiteboard go-to. It might not work for you, but let&#8217;s try it:<\/p>\n<p>Below is an iteration of <a href=\"https:\/\/blog.mozilla.org\/webrtc\/fiddle-week-spec-compliant-getstats\/\">last week&#8217;s Fiddle-of-the-week on <code>getStats<\/code><\/a> rewritten to be opened in two adjacent tabs, using <code>async<\/code>\/<code>await<\/code>. Transmitting across tabs is not only more impressive, but also more real-world-like: we only deal with one side and signal the other. The example also uses destructuring, in addition to template strings from last week, two other modern JS features, to keep it interesting.<\/p>\n<p>There are two parts. The immediately visible part covers connection entirely. Later, scroll down to see the <a href=\"https:\/\/blog.mozilla.org\/webrtc\/fiddle-week-spec-compliant-getstats\/\"><code>getStats<\/code><\/a> loop.<\/p>\n<p>To see it in action, first <a href=\"https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/\">right-click here and open this post in a second window<\/a>. Next, activate the \u201cResult\u201d tab in both windows, and finally come back here and hit the \u201cCall\u201d button!<\/p>\n<p><iframe loading=\"lazy\" src=\"https:\/\/jsfiddle.net\/jib1\/qtg2x9tc\/embedded\/js,result,html\/\" width=\"100%\" height=\"690px\" frameborder=\"0\"><\/iframe><\/p>\n<p>This works in Firefox 52 and Chrome Canary. You should see it ask for your camera and transmit the video to the other window, as well as a running tally of statistics on both ends.<\/p>\n<h4>Highlights<\/h4>\n<p>Look how straightforward making an offer is now:<\/p>\n<pre class=\"tCont active hljs javascript\">  <span class=\"hljs-keyword\">await<\/span> pc.setLocalDescription(<span class=\"hljs-keyword\">await<\/span> pc.createOffer());\r\n  sc.send({sdp: pc.localDescription});\r\n<\/pre>\n<p>It\u2019s written as we&#8217;d explain it: <em>\u201cWe set our connection\u2019s local description to an offer, and send it to the other side on our signaling channel.\u201d<\/em> It becomes a detail that some steps are asynchronous (even though they&#8217;re still clearly marked).<\/p>\n<p>Scrolling down to the next function above, it&#8217;s our loop for polling of statistics:<\/p>\n<pre class=\"tCont active hljs javascript\">    <span class=\"hljs-keyword\">while<\/span> (<span class=\"hljs-literal\">true<\/span>) {\r\n      <span class=\"hljs-keyword\">let<\/span> html = <span class=\"hljs-string\">\"\"<\/span>, stats = <span class=\"hljs-keyword\">await<\/span> pc.getStats();\r\n      <span class=\"hljs-keyword\">for<\/span> (<span class=\"hljs-keyword\">let<\/span> stat <span class=\"hljs-keyword\">of<\/span> stats.values()) {\r\n        <span class=\"hljs-keyword\">if<\/span> (stat.isRemote) <span class=\"hljs-keyword\">continue<\/span>;\r\n        <span class=\"hljs-keyword\">switch<\/span> (stat.type) {\r\n          <span class=\"hljs-keyword\">case<\/span> <span class=\"hljs-string\">\"outbound-rtp\"<\/span>: {\r\n            html += dumpOutbound(stat) + <span class=\"hljs-string\">\"&lt;br&gt;\"<\/span>;\r\n            <span class=\"hljs-keyword\">let<\/span> rtcp = stats.get(stat.remoteId);\r\n            <span class=\"hljs-keyword\">if<\/span> (rtcp) html += <span class=\"hljs-string\">\"RTCP \"<\/span> + dumpInbound(rtcp) + <span class=\"hljs-string\">\"&lt;br&gt;\"<\/span>;\r\n            <span class=\"hljs-keyword\">break<\/span>;\r\n          }\r\n<\/pre>\n<p>The code is no longer structured around synchronization points, getting straight to the meat of building our output. Here&#8217;s a <a href=\"https:\/\/jsfiddle.net\/jib1\/4ea0nj0s\/\">cheat-sheet<\/a> on <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Map\">Maplike<\/a> behavior, if you need it.<\/p>\n<p>Notice we use a <code>for-of<\/code> loop instead of <code>forEach<\/code>. The importance of doing so isn&#8217;t immediately obvious here, but it&#8217;s worth calling out: Should we later need to use the <code>await<\/code> keyword inside the loop, it&#8217;ll work right! <code>forEach<\/code> on the other hand, would betray us, as it takes a function, and doesn&#8217;t know about <code>async<\/code> functions. It&#8217;s also nice to use <code>continue<\/code> and <code>return<\/code> again, a revival of iterative programming.<\/p>\n<pre class=\"tCont active hljs javascript\">      <span class=\"hljs-keyword\">await<\/span> wait(<span class=\"hljs-number\">100<\/span>);\r\n    }<\/pre>\n<p>We sleep 100 milliseconds and loop, which importantly does not busy-wait, but uses <code>setTimeout<\/code> (see the one-line <code>wait<\/code> function). While <code>setInterval<\/code> would perhaps provide more reliable timing, we avoid its error-handling traps, and avoid starving slow systems. We also abort correctly in case of error instead of leaving &#8220;running-fan log spew&#8221; to use a euphemism. But the main point here is illustration: In general, looping asynchronous sequences is wildly complicated to pull off with callbacks and even recursive promise-chains. I can\u2019t tell you how many stackoverflow questions I\u2019ve seen on this. Now it just works.<\/p>\n<p>Best of all, errors are now handled the same for synchronous and asynchronous code, using good-old <code>try{}<\/code><code>catch(){}<\/code>. They may not win points for compactness, but as much as I hate to admit it, compactness is sometimes overrated.<\/p>\n<h4>Planning ahead<\/h4>\n<p>Even though it may be a while before you can use <code>async<\/code>\/<code>await<\/code> in your organization, know that all browsers that support WebRTC support promises now. This means that once you&#8217;ve feature-detected WebRTC, you can use promises (use <a href=\"https:\/\/github.com\/webrtc\/adapter\">adapter.js<\/a> to cover older versions)!<\/p>\n<p>Converting <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Guide\/Using_promises\">promise<\/a> code to\u00a0<code>async<\/code>\/<code>await<\/code> later should be trivial. Unfortunately, a lot of WebRTC code we see on the web still uses the legacy callback APIs, which bites. So if you want to prepare, take a moment to update your code to promises now. Your future self will thank you. Safe transmissions!<\/p>\n","protected":false},"excerpt":{"rendered":"This isn&#8217;t a post about a new WebRTC feature. Rather, we&#8217;ll explore the new async\/await JavaScript syntax in the just-released Firefox 52 and Chrome! Two new keywords let us write asynchronous code the same way we&#8217;d write synchronous code. WebRTC APIs, as you&#8217;re probably aware, are quite asynchronous. Luckily they support promises &#8211; a requirement [&hellip;]","protected":false},"author":1399,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"coauthors":[301098],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Fiddle-of-the-week: await WebRTC in Firefox 52 - Advancing WebRTC<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Fiddle-of-the-week: await WebRTC in Firefox 52 - Advancing WebRTC\" \/>\n<meta property=\"og:description\" content=\"This isn&#8217;t a post about a new WebRTC feature. Rather, we&#8217;ll explore the new async\/await JavaScript syntax in the just-released Firefox 52 and Chrome! Two new keywords let us write asynchronous code the same way we&#8217;d write synchronous code. WebRTC APIs, as you&#8217;re probably aware, are quite asynchronous. Luckily they support promises &#8211; a requirement [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/\" \/>\n<meta property=\"og:site_name\" content=\"Advancing WebRTC\" \/>\n<meta property=\"article:published_time\" content=\"2017-03-13T15:46:32+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2018-08-01T19:24:14+00:00\" \/>\n<meta name=\"author\" content=\"Jan-Ivar Bruaroey\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jan-Ivar Bruaroey\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/\",\"url\":\"https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/\",\"name\":\"Fiddle-of-the-week: await WebRTC in Firefox 52 - Advancing WebRTC\",\"isPartOf\":{\"@id\":\"https:\/\/blog.mozilla.org\/webrtc\/#website\"},\"datePublished\":\"2017-03-13T15:46:32+00:00\",\"dateModified\":\"2018-08-01T19:24:14+00:00\",\"author\":{\"@id\":\"https:\/\/blog.mozilla.org\/webrtc\/#\/schema\/person\/f2eb9712b8d85b70aebe1faf24e731fd\"},\"breadcrumb\":{\"@id\":\"https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blog.mozilla.org\/webrtc\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Fiddle-of-the-week: await WebRTC in Firefox 52\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blog.mozilla.org\/webrtc\/#website\",\"url\":\"https:\/\/blog.mozilla.org\/webrtc\/\",\"name\":\"Advancing WebRTC\",\"description\":\"Committed to moving Firefox and WebRTC forward\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blog.mozilla.org\/webrtc\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blog.mozilla.org\/webrtc\/#\/schema\/person\/f2eb9712b8d85b70aebe1faf24e731fd\",\"name\":\"Jan-Ivar Bruaroey\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/blog.mozilla.org\/webrtc\/#\/schema\/person\/image\/5f3d49a61b032619d0d33c4cc7c7433f\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/16d7e05dc9f8a855a02e0796b00aad3f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/16d7e05dc9f8a855a02e0796b00aad3f?s=96&d=mm&r=g\",\"caption\":\"Jan-Ivar Bruaroey\"},\"url\":\"https:\/\/blog.mozilla.org\/webrtc\/author\/jbruaroeymozilla-com\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Fiddle-of-the-week: await WebRTC in Firefox 52 - Advancing WebRTC","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/","og_locale":"en_US","og_type":"article","og_title":"Fiddle-of-the-week: await WebRTC in Firefox 52 - Advancing WebRTC","og_description":"This isn&#8217;t a post about a new WebRTC feature. Rather, we&#8217;ll explore the new async\/await JavaScript syntax in the just-released Firefox 52 and Chrome! Two new keywords let us write asynchronous code the same way we&#8217;d write synchronous code. WebRTC APIs, as you&#8217;re probably aware, are quite asynchronous. Luckily they support promises &#8211; a requirement [&hellip;]","og_url":"https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/","og_site_name":"Advancing WebRTC","article_published_time":"2017-03-13T15:46:32+00:00","article_modified_time":"2018-08-01T19:24:14+00:00","author":"Jan-Ivar Bruaroey","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Jan-Ivar Bruaroey","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/","url":"https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/","name":"Fiddle-of-the-week: await WebRTC in Firefox 52 - Advancing WebRTC","isPartOf":{"@id":"https:\/\/blog.mozilla.org\/webrtc\/#website"},"datePublished":"2017-03-13T15:46:32+00:00","dateModified":"2018-08-01T19:24:14+00:00","author":{"@id":"https:\/\/blog.mozilla.org\/webrtc\/#\/schema\/person\/f2eb9712b8d85b70aebe1faf24e731fd"},"breadcrumb":{"@id":"https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/blog.mozilla.org\/webrtc\/fiddle-of-the-week-await\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blog.mozilla.org\/webrtc\/"},{"@type":"ListItem","position":2,"name":"Fiddle-of-the-week: await WebRTC in Firefox 52"}]},{"@type":"WebSite","@id":"https:\/\/blog.mozilla.org\/webrtc\/#website","url":"https:\/\/blog.mozilla.org\/webrtc\/","name":"Advancing WebRTC","description":"Committed to moving Firefox and WebRTC forward","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.mozilla.org\/webrtc\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/blog.mozilla.org\/webrtc\/#\/schema\/person\/f2eb9712b8d85b70aebe1faf24e731fd","name":"Jan-Ivar Bruaroey","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blog.mozilla.org\/webrtc\/#\/schema\/person\/image\/5f3d49a61b032619d0d33c4cc7c7433f","url":"https:\/\/secure.gravatar.com\/avatar\/16d7e05dc9f8a855a02e0796b00aad3f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/16d7e05dc9f8a855a02e0796b00aad3f?s=96&d=mm&r=g","caption":"Jan-Ivar Bruaroey"},"url":"https:\/\/blog.mozilla.org\/webrtc\/author\/jbruaroeymozilla-com\/"}]}},"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/webrtc\/wp-json\/wp\/v2\/posts\/269"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/webrtc\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/webrtc\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/webrtc\/wp-json\/wp\/v2\/users\/1399"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/webrtc\/wp-json\/wp\/v2\/comments?post=269"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/webrtc\/wp-json\/wp\/v2\/posts\/269\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/webrtc\/wp-json\/wp\/v2\/media?parent=269"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/webrtc\/wp-json\/wp\/v2\/categories?post=269"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/webrtc\/wp-json\/wp\/v2\/tags?post=269"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blog.mozilla.org\/webrtc\/wp-json\/wp\/v2\/coauthors?post=269"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}