| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]--> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <meta name="generator" content="Asciidoctor 1.5.7.1"> |
| <title>Async/Await</title> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> |
| <!-- ************* Meta ************* --> |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> |
| |
| <!-- ************* OpenGraph ************--> |
| <meta name="description" content="The Eclipse N4JS language and its IDE enable high-quality JavaScript development for large Node.js projects."> |
| |
| <meta property="og:site_name" content="Eclipse N4JS"/> |
| <meta property="og:title" content="Eclipse N4JS Language and IDE"/> |
| <meta property="og:url" content="https://numberfour.github.io/n4js"/> |
| <meta property="og:description" content="The Eclipse N4JS language and its IDE enable high-quality JavaScript development for large Node.js projects."/> |
| <meta property="og:image" content="../images/n4js.png"> |
| |
| <!-- ************* Favicon ************--> |
| <link rel="icon" href="../images/favicon.ico" /> |
| <link rel="icon" type="image/png" href="../images/favicon-32x32.png" sizes="32x32" /> |
| <link rel="icon" type="image/png" href="../images/favicon-16x16.png" sizes="16x16" /> |
| |
| <!-- ************* Back-to-top JQuery ************* --> |
| <script src="https://code.jquery.com/jquery-1.12.4.js"></script> |
| <script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script> |
| |
| <!-- ************* Prism.js Syntax Highlighter ******--> |
| <link href="../styles/prism.min.css" rel="stylesheet"/> |
| <script src="../scripts/prism.js"></script> |
| |
| <!-- ************* Styles ************* --> |
| |
| <link rel="stylesheet" type="text/css" href="../styles/n4js-adoc.css"> |
| |
| <!-- ****************** NavBar ****************** --> |
| <div id="menubar"> |
| <div class="banner"> |
| <a href="../index.html"><img id="logo" src="../images/n4js-logo.png" alt="Eclipse N4JS Language and IDE"></a> |
| </div> |
| <ul> |
| <li><a href="../downloads.html"></i>Download</a></li> |
| <li><a href="../community.html"></i>Community</a></li> |
| <li><a href="../userguides/index.html">Documentation</a></li> |
| </ul> |
| </div> |
| <button id="tocbutton">TOC</button> |
| </head> |
| <body class="book"> |
| <div id="header"> |
| </div> |
| <div id="content"> |
| <h1 id="_asyncawait" class="sect0"><a class="link" href="#_asyncawait">Async/Await</a></h1> |
| <div class="openblock partintro"> |
| <div class="content"> |
| <div class="paragraph"> |
| <div class="title">Async/Await</div> |
| <p>Due to the event-driven nature inherent in JavaScript, asynchronous code has |
| always been explicit and verbose, leading to projects which are hard to read and maintain. |
| N4JS already implements the async/await proposal and it provides additional features allowing |
| the use of legacy code in combination with await and promises.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Over the years, growing trends have been to migrate from |
| simple callbacks to Promise objects which is making the chaining of asynchronous data |
| flows easier. This still urges the developer to implement callbacks on |
| the resolution of a Promise.</p> |
| </div> |
| <div class="paragraph"> |
| <p>N4JS implements a new approach proposed by TC39 on <a href="https://tc39.github.io/ecmascript-asyncawait/">async functions</a> |
| to tackle the problem. It conceals the drawn-out details and formal approach so that a |
| developer would have less code to write. A function or method can essentially become an |
| <strong>asynchronous</strong> function by prepending the keyword <code>async</code>. |
| Inside the function, the developer can call other functions and wait for their |
| results using the keyword <code>async</code>:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">async function foo(): int { |
| let res = await anotherAsyncFunction(); |
| ++res; |
| return res; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The benefit here is that async functions integrate well with any existing |
| Promise-based APIs, i.e. N4JS treats any return type <strong>T</strong> of an async method |
| or function as a <strong>Promise<T, any></strong>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>On the other hand, async code can simply await on functions that return a Promise |
| object:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">function fetch(url: string): Promise<Response, any> { |
| // WHATWG fetch |
| return null; |
| } |
| |
| async function foo() { |
| let html = await (await fetch('http://www.google.com')).text(); |
| console.log(html); |
| }</code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_error_handling"><a class="link" href="#_error_handling">Error Handling</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Since there’s a one-to-one mapping to Promises, exceptions being thrown within |
| an async function call are rejecting the corresponding Promise:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">function throwr() { return Promise.reject(new Error('bah!')); } |
| |
| async function foo() { |
| try { |
| await throwr(); |
| } catch (err) { |
| (err as Error).message === 'bah!'; |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>A rejected Promise will be reflected as an exception being thrown in the |
| async function:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">async function throwr() { throw new Error('bah!'); } |
| let promise: Promise<void, ?> = throwr(); |
| |
| promise.catch(err => (err as Error).message === 'bah!');</code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_await_for_legacy_code"><a class="link" href="#_await_for_legacy_code">"await" for Legacy Code</a></h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>There’s quite a lot of callback-driven code alive that is not returning Promises, |
| especially with reference to Node.js core modules:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import * as fs from 'fs'; |
| |
| fs.readFile('myFile.txt', (err, content) => { |
| if (err) throw err; |
| console.log(content); |
| })</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This code follows the general Node.js callback pattern of passing the error as |
| a first argument following the result value(s).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Since N4JS encourages you to use and define types where possible, we can do |
| better here, too. N4JS allows to use the <strong>@Promisifiable</strong> annotation in this |
| case (and actually the Node.js runtime definitions provided by N4JS already make use of it):</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">@Promisifiable |
| export external public function readFile( |
| filename: string, |
| options: ~Object with {encoding: string?; flag: string?;}, |
| callback: {function(Error, string)}?): void;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This allows to call the function without implementing any callback, and let the |
| transpiler wire up a Promise for you using the <strong>@Promisify</strong> annotation:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { readFile } from 'fs'; |
| |
| function foo(): Promise<string, any> { |
| var promise = @Promisify readFile('myFile.txt', { encoding: 'UTF-8' }); |
| return promise.then(content => content.replace(/foo/g, 'bar')); |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Since promises integrate with async functions, we could even further |
| condense this down:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { readFile } from 'fs'; |
| |
| async function foo(): string { |
| var content = await readFile('myFile.txt', { encoding: 'UTF-8' }); |
| return content.replace(/foo/g, 'bar'); |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Finally, it’s noteworthy to mention that arrow functions can work asynchronously as well, |
| which is particularly helpful. The following example demonstrates how we can easily test async |
| code to throw an error using an async arrow expression in the context of the N4JS test framework "mangelhaft".</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-n4js" data-lang="n4js">import { Assert } from 'n4/mangel/assert/Assert'; |
| |
| export public class FooTest { |
| |
| @Test async myTest() { |
| await Assert.throwsAsync(async () => { |
| // async piece of code that is throwing an error |
| }); |
| } |
| |
| }</code></pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div id="footer"> |
| <div id="footer-text"> |
| </div> |
| </div> |
| <div class="Grid social" style="color:#d5dfea"> |
| <div class="Cell Cell--2-12 m-Cell--withMargin"> |
| <h2>Quick Links</h2> |
| <ul> |
| <li><a href="../downloads.html">Download</a></li> |
| <li><a href="../userguides/index.html">Documentation</a></li> |
| <li><a href="https://github.com/eclipse/n4js/">Source</a></li> |
| <li><a href="https://github.com/eclipse/n4js/issues">Issues</a></li> |
| </ul> |
| </div> |
| <div class="Cell Cell--2-12 m-Cell--withMargin"> |
| <br/><br/> |
| <ul> |
| <li><a href="https://www.eclipse.org/forums/index.php/f/365/">Forum</a></li> |
| <li><a href="http://n4js.blogspot.de/">Blog</a></li> |
| <li><a href="https://dev.eclipse.org/mailman/listinfo/n4js-dev">Mailing List</a></li> |
| <li><a href="https://projects.eclipse.org/projects/technology.n4js">Eclipse Project Page</a></li> |
| <li><a href="https://twitter.com/n4jsdev">Tweets by n4jsdev</a></li> |
| </ul> |
| </div> |
| <div class="Cell Cell--2-12 m-Cell--withMargin"> |
| <br/><br/> |
| <ul> |
| <li><a href="http://www.eclipse.org/">Eclipse Home</a></li> |
| <li><a href="http://www.eclipse.org/legal/privacy.php">Privacy Policy</a></li> |
| <li><a href="http://www.eclipse.org/legal/termsofuse.php">Terms of Use</a></li> |
| <li><a href="http://www.eclipse.org/legal/copyright.php">Copyright Agent</a></li> |
| <li><a href="http://www.eclipse.org/legal/">Legal</a></li> |
| </ul> |
| </div> |
| <div style="clear: both; height: 0; overflow: hidden;"></div> |
| </div> |
| |
| <script> |
| // Toggle the table of contents |
| $( "button#tocbutton" ).click(function() { |
| if ($("#tocbutton").css('right') == '25px') { |
| $( "#tocbutton" ).animate({right: '215px'},"slow"); |
| $( "#toc.toc2" ).animate({right: '0'},"slow"); |
| } |
| else { |
| $( "#tocbutton" ).animate({right: '25px'},"slow"); |
| $( "#toc.toc2" ).animate({right: '-13rem'},"slow"); |
| } |
| }); |
| </script> |
| |
| <script type="text/javascript"> |
| // Create a back to top button |
| $('body').prepend('<a href="#" class="back-to-top">Back to Top</a>'); |
| var amountScrolled = 300; |
| $(window).scroll(function() { |
| if ( $(window).scrollTop() > amountScrolled ) { |
| $('a.back-to-top').fadeIn('slow'); |
| } else { |
| $('a.back-to-top').fadeOut('slow'); |
| } |
| }); |
| $('a.back-to-top, a.simple-back-to-top').click(function() { |
| $('html, body').animate({ |
| scrollTop: 0 |
| }, 700); |
| return false; |
| }); |
| </script> |
| </body> |
| </html> |