<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/an-example-of-how-to-use-the-new-r-promises-package/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://appsilondatascience.com/blog/rstats/2017/11/01/r-promises-hands-on.html"> Appsilon Data Science Blog</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p><strong>The long awaited promises will be released soon!<strong></strong></strong></p>
<p><img alt="Can't wait to play with promises :)" src="https://i2.wp.com/appsilondatascience.com/blog/assets/article_images/2017-11-01-r-promises-hands-on/yay.gif?w=456" data-recalc-dims="1"></p>
<p>Being as impatient as I am when it comes to new technology, I decided to play with currently available implementation of promises that Joe Cheng shared and presented recently in London at <a rel="nofollow" href="https://earlconf.com/london/" target="_blank">EARL conference</a>.</p>
<p>From this article you’ll get to know the upcoming <code>promises</code> package, how to use it and how it is different from the already existing <code>future</code> package.</p>
<p>Promises/Futures are a concept used in almost every major programming language. We’ve used Tasks in C#, Futures in Scala, Promises in Javascript and they all adhere to a common understanding of what a promise is.</p>
<p>If you are not familiar with the concept of Promises, asynchronous tasks or Futures, I advise you to take a longer moment and dive into the topic. If you’d like to dive deeper and achieve a higher level of understanding, read about Continuation Monads in Haskell. We’ll be comparing the new <code>promises</code> package with the <code>future</code> package, which has been around for a while so I suggest you take a look at it <a rel="nofollow" href="https://cran.r-project.org/web/packages/future/vignettes/future-1-overview.html" target="_blank">https://cran.r-project.org/web/packages/future/vignettes/future-1-overview.html</a> first if you haven’t used it before.</p>
<p>Citing Joe Cheng, our aim is to:</p>
<ol>
<li>Execute long-running code asynchronously on separate thread.</li>
<li>Be able to do something with the result (if success) or error (if failure), when the task completes, back on the main R thread.</li>
</ol>
<p>A promise object represents the eventual result of an async task. A promise is an R6 object that knows:</p>
<ol>
<li>Whether the task is running, succeeded, or failed</li>
<li>The result (if succeeded) or error (if failed)</li>
</ol>
<hr>
<p><strong>Without further ado, let’s get our hands on the code!</strong> You should be able to just copy-paste code into RStudio and run it.</p>
<p>R is single threaded. This means that user cannot interact with your shiny app if there is a long running task being executed on the server. Let’s take a look at an example:</p>
<figure>
<pre><code data-lang="r"><span>longRunningFunction</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>value</span><span>)</span><span> </span><span>{</span><span>
</span><span>Sys.sleep</span><span>(</span><span>5</span><span>)</span><span>
</span><span>return</span><span>(</span><span>value</span><span>)</span><span>
</span><span>}</span><span>
</span><span>a</span><span> </span><span>&lt;-</span><span> </span><span>longRunningFunction</span><span>(</span><span>1</span><span>)</span><span>
</span><span>b</span><span> </span><span>&lt;-</span><span> </span><span>longRunningFunction</span><span>(</span><span>2</span><span>)</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span><span> </span><span># Time: 10s
</span><span>c</span><span> </span><span>&lt;-</span><span> </span><span>longRunningFunction</span><span>(</span><span>10</span><span>)</span><span>
</span><span>print</span><span>(</span><span>a</span><span>)</span><span>
</span><span>print</span><span>(</span><span>b</span><span>)</span><span>
</span><span>sumAC</span><span> </span><span>&lt;-</span><span> </span><span>a</span><span> </span><span>+</span><span> </span><span>c</span><span>
</span><span>sumBC</span><span> </span><span>&lt;-</span><span> </span><span>b</span><span> </span><span>+</span><span> </span><span>c</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span><span> </span><span># Time: 15s
</span><span>print</span><span>(</span><span>sumAC</span><span> </span><span>+</span><span> </span><span>sumBC</span><span>)</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span><span> </span><span>#</span><span> </span><span>Time</span><span>:</span><span> </span><span>15</span><span>s</span></code></pre>
</figure>
<p>We’ll use a simplified version of user interaction while there are some additional computations happening on the server. Let’s assume that we can’t just put all the computations in a separate block of code and just run it separately using the <code>future</code> package. There are many cases when it is very difficult or even almost impossible to just gather all computations and run them elsewhere as one big long block of code.</p>
<p>User cannot interact with the app for 10 seconds until the computations are finished and then the user has to wait another 5 seconds for next interaction. This is not a place where we would like to be in. User interactions should be as fast as possible and the user shouldn’t have to wait if it is not required. Let’s fix that using R <code>future</code> package that we know.</p>
<figure>
<pre><code data-lang="r"><span>install.packages</span><span>(</span><span>&quot;future&quot;</span><span>)</span><span>
</span><span>library</span><span>(</span><span>future</span><span>)</span><span>
</span><span>plan</span><span>(</span><span>multiprocess</span><span>)</span><span>
</span><span>longRunningFunction</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>value</span><span>)</span><span> </span><span>{</span><span>
</span><span>Sys.sleep</span><span>(</span><span>5</span><span>)</span><span>
</span><span>return</span><span>(</span><span>value</span><span>)</span><span>
</span><span>}</span><span>
</span><span>a</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>longRunningFunction</span><span>(</span><span>1</span><span>))</span><span>
</span><span>b</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>longRunningFunction</span><span>(</span><span>2</span><span>))</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span><span> </span><span># Time: 0s
</span><span>c</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>longRunningFunction</span><span>(</span><span>10</span><span>))</span><span>
</span><span>print</span><span>(</span><span>value</span><span>(</span><span>a</span><span>))</span><span>
</span><span>print</span><span>(</span><span>value</span><span>(</span><span>b</span><span>))</span><span>
</span><span>sumAC</span><span> </span><span>&lt;-</span><span> </span><span>value</span><span>(</span><span>a</span><span>)</span><span> </span><span>+</span><span> </span><span>value</span><span>(</span><span>c</span><span>)</span><span>
</span><span>sumBC</span><span> </span><span>&lt;-</span><span> </span><span>value</span><span>(</span><span>b</span><span>)</span><span> </span><span>+</span><span> </span><span>value</span><span>(</span><span>c</span><span>)</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span><span> </span><span># Time: 5s
</span><span>print</span><span>(</span><span>sumAC</span><span> </span><span>+</span><span> </span><span>sumBC</span><span>)</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span><span> </span><span>#</span><span> </span><span>Time</span><span>:</span><span> </span><span>5</span><span>s</span></code></pre>
</figure>
<p>Nice, now the first user interaction can happen in parallel! But the second interaction is still blocked – we have to wait for the values, to print their sum. In order to fix that we’d like to chain the computation into the summing function instead of waiting synchronously for the result. We can’t do that using pure futures though (assuming we can’t just put all these computations in one single block of code and run it in parallel). Ideally we’d like to be able to write code similar to the one below:</p>
<figure>
<pre><code data-lang="r"><span>library</span><span>(</span><span>future</span><span>)</span><span>
</span><span>plan</span><span>(</span><span>multiprocess</span><span>)</span><span>
</span><span>longRunningFunction</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>value</span><span>)</span><span> </span><span>{</span><span>
</span><span>Sys.sleep</span><span>(</span><span>5</span><span>)</span><span>
</span><span>return</span><span>(</span><span>value</span><span>)</span><span>
</span><span>}</span><span>
</span><span>a</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>longRunningFunction</span><span>(</span><span>1</span><span>))</span><span>
</span><span>b</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>longRunningFunction</span><span>(</span><span>2</span><span>))</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span><span> </span><span># Time: 0s
</span><span>c</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>longRunningFunction</span><span>(</span><span>10</span><span>))</span><span>
</span><span>future</span><span>(</span><span>print</span><span>(</span><span>value</span><span>(</span><span>a</span><span>)))</span><span>
</span><span>future</span><span>(</span><span>print</span><span>(</span><span>value</span><span>(</span><span>b</span><span>)))</span><span>
</span><span>sumAC</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>value</span><span>(</span><span>a</span><span>)</span><span> </span><span>+</span><span> </span><span>value</span><span>(</span><span>c</span><span>))</span><span>
</span><span>sumBC</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>value</span><span>(</span><span>b</span><span>)</span><span> </span><span>+</span><span> </span><span>value</span><span>(</span><span>c</span><span>))</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span><span> </span><span># Time: 0s
</span><span>future</span><span>(</span><span>print</span><span>(</span><span>value</span><span>(</span><span>sumAC</span><span>)</span><span> </span><span>+</span><span> </span><span>value</span><span>(</span><span>sumBC</span><span>)))</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span><span> </span><span>#</span><span> </span><span>Time</span><span>:</span><span> </span><span>0</span><span>s</span></code></pre>
</figure>
<p>Unfortunately <code>future</code> package won’t allow us to do that.</p>
<hr>
<p>What we can do, is use the <a rel="nofollow" href="https://github.com/rstudio/promises" target="_blank">promises</a> package from RStudio!</p>
<figure>
<pre><code data-lang="r"><span>devtools</span><span>::</span><span>install_github</span><span>(</span><span>&quot;rstudio/promises&quot;</span><span>)</span></code></pre>
</figure>
<hr>
<p><strong>Let’s play with the promises!</strong> I simplified our example to let us focus on using promises first:</p>
<figure>
<pre><code data-lang="r"><span>library</span><span>(</span><span>future</span><span>)</span><span>
</span><span>plan</span><span>(</span><span>multiprocess</span><span>)</span><span>
</span><span>library</span><span>(</span><span>tibble</span><span>)</span><span>
</span><span>longRunningFunction</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>value</span><span>)</span><span> </span><span>{</span><span>
</span><span>Sys.sleep</span><span>(</span><span>5</span><span>)</span><span>
</span><span>return</span><span>(</span><span>value</span><span>)</span><span>
</span><span>}</span><span>
</span><span>a</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>longRunningFunction</span><span>(</span><span>tibble</span><span>(</span><span>number</span><span> </span><span>=</span><span> </span><span>1</span><span>:</span><span>100</span><span>)))</span><span>
</span><span>print</span><span>(</span><span>value</span><span>(</span><span>a</span><span>))</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span><span> </span><span>#</span><span> </span><span>Time</span><span>:</span><span> </span><span>5</span><span>s</span></code></pre>
</figure>
<p>We’d like to chain the result of <code>longRunningFunction</code> to a print function so that once the <code>longRunningFunction</code> is finished, its results are printed.</p>
<p>We can achieve that by using %…>% operator. It works like the very popular <a rel="nofollow" href="https://cran.r-project.org/web/packages/magrittr/vignettes/magrittr.html" target="_blank">%>% operator from magrittr</a>. Think of <code>%...>%</code> as “sometime in the future, once I have the result of the operation, pass the result to the next function”. The three dots symbolise the fact that we have to wait and that the result will be passed in future, it’s not happening now.</p>
<figure>
<pre><code data-lang="r"><span>library</span><span>(</span><span>future</span><span>)</span><span>
</span><span>plan</span><span>(</span><span>multiprocess</span><span>)</span><span>
</span><span>library</span><span>(</span><span>promises</span><span>)</span><span>
</span><span>library</span><span>(</span><span>tibble</span><span>)</span><span>
</span><span>longRunningFunction</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>value</span><span>)</span><span> </span><span>{</span><span>
</span><span>Sys.sleep</span><span>(</span><span>5</span><span>)</span><span>
</span><span>return</span><span>(</span><span>value</span><span>)</span><span>
</span><span>}</span><span>
</span><span>a</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>longRunningFunction</span><span>(</span><span>tibble</span><span>(</span><span>number</span><span> </span><span>=</span><span> </span><span>1</span><span>:</span><span>100</span><span>)))</span><span>
</span><span>a</span><span> </span><span>%...>%</span><span>
</span><span>print</span><span>()</span><span> </span><span># Time: 5s
</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span><span> </span><span>#</span><span> </span><span>Time</span><span>:</span><span> </span><span>0</span><span>s</span></code></pre>
</figure>
<p>Pure magic.</p>
<p>But what if I want to filter the result first and then print the processed data? Just keep on chaining:</p>
<figure>
<pre><code data-lang="r"><span>library</span><span>(</span><span>future</span><span>)</span><span>
</span><span>plan</span><span>(</span><span>multiprocess</span><span>)</span><span>
</span><span>library</span><span>(</span><span>promises</span><span>)</span><span>
</span><span>library</span><span>(</span><span>tibble</span><span>)</span><span>
</span><span>library</span><span>(</span><span>dplyr</span><span>)</span><span>
</span><span>longRunningFunction</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>value</span><span>)</span><span> </span><span>{</span><span>
</span><span>Sys.sleep</span><span>(</span><span>5</span><span>)</span><span>
</span><span>return</span><span>(</span><span>value</span><span>)</span><span>
</span><span>}</span><span>
</span><span>a</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>longRunningFunction</span><span>(</span><span>tibble</span><span>(</span><span>number</span><span> </span><span>=</span><span> </span><span>1</span><span>:</span><span>100</span><span>)))</span><span>
</span><span>a</span><span> </span><span>%...>%</span><span>
</span><span>filter</span><span>(</span><span>number</span><span> </span><span>%%</span><span> </span><span>2</span><span> </span><span>==</span><span> </span><span>1</span><span>)</span><span> </span><span>%...>%</span><span>
</span><span>sum</span><span>()</span><span> </span><span>%...>%</span><span>
</span><span>print</span><span>()</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span></code></pre>
</figure>
<p>Neat. But, how can I print the result of filtering and pass it to the <code>sum</code> function? There is a tee operator, the same as the one magrittr provides (but one that operates on a promise). It will pass the result of the function to the next function. If you chain it further, it will not pass the result of <code>print()</code> function but previous results. Think of it as splitting a railway, printing the value on a side track and ending the run, then getting back to the main track:</p>
<figure>
<pre><code data-lang="r"><span>library</span><span>(</span><span>future</span><span>)</span><span>
</span><span>plan</span><span>(</span><span>multiprocess</span><span>)</span><span>
</span><span>library</span><span>(</span><span>promises</span><span>)</span><span>
</span><span>library</span><span>(</span><span>tibble</span><span>)</span><span>
</span><span>library</span><span>(</span><span>dplyr</span><span>)</span><span>
</span><span>longRunningFunction</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>value</span><span>)</span><span> </span><span>{</span><span>
</span><span>Sys.sleep</span><span>(</span><span>5</span><span>)</span><span>
</span><span>return</span><span>(</span><span>value</span><span>)</span><span>
</span><span>}</span><span>
</span><span>a</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>longRunningFunction</span><span>(</span><span>tibble</span><span>(</span><span>number</span><span> </span><span>=</span><span> </span><span>1</span><span>:</span><span>100</span><span>)))</span><span>
</span><span>a</span><span> </span><span>%...>%</span><span>
</span><span>filter</span><span>(</span><span>number</span><span> </span><span>%%</span><span> </span><span>2</span><span> </span><span>==</span><span> </span><span>1</span><span>)</span><span> </span><span>%...T>%</span><span>
</span><span>print</span><span>()</span><span> </span><span>%...>%</span><span>
</span><span>sum</span><span>()</span><span> </span><span>%...>%</span><span>
</span><span>print</span><span>()</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span></code></pre>
</figure>
<p>What about errors? They are being thrown somewhere else than in the main thread, how can I catch them? You guessed it – there is an operator for that as well. Use <code>%...!%</code> to handle errors:</p>
<figure>
<pre><code data-lang="r"><span>library</span><span>(</span><span>future</span><span>)</span><span>
</span><span>plan</span><span>(</span><span>multiprocess</span><span>)</span><span>
</span><span>library</span><span>(</span><span>promises</span><span>)</span><span>
</span><span>library</span><span>(</span><span>tibble</span><span>)</span><span>
</span><span>library</span><span>(</span><span>dplyr</span><span>)</span><span>
</span><span>longRunningFunction</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>value</span><span>)</span><span> </span><span>{</span><span>
</span><span>stop</span><span>(</span><span>&quot;ERROR&quot;</span><span>)</span><span>
</span><span>return</span><span>(</span><span>value</span><span>)</span><span>
</span><span>}</span><span>
</span><span>a</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>longRunningFunction</span><span>(</span><span>tibble</span><span>(</span><span>number</span><span> </span><span>=</span><span> </span><span>1</span><span>:</span><span>100</span><span>)))</span><span>
</span><span>a</span><span> </span><span>%...>%</span><span>
</span><span>filter</span><span>(</span><span>number</span><span> </span><span>%%</span><span> </span><span>2</span><span> </span><span>==</span><span> </span><span>1</span><span>)</span><span> </span><span>%...T>%</span><span>
</span><span>print</span><span>()</span><span> </span><span>%...>%</span><span>
</span><span>sum</span><span>()</span><span> </span><span>%...>%</span><span>
</span><span>print</span><span>()</span><span> </span><span>%...!%</span><span>
</span><span>(</span><span>function</span><span>(</span><span>error</span><span>)</span><span> </span><span>{</span><span>
</span><span>print</span><span>(</span><span>paste</span><span>(</span><span>&quot;Unexpected error: &quot;</span><span>,</span><span> </span><span>error</span><span>$</span><span>message</span><span>))</span><span>
</span><span>})</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span></code></pre>
</figure>
<p>But in our example we’re not just chaining one computation. There is a <code>longRunningFunction</code> call that eventually returns 1 and another one that eventually returns 2. We need to somehow join the two. Once both of them are ready, we’d like to use them and return the sum. We can use <code>promise_all</code> function to achieve that. It takes a list of promises as an argument and returns a promise that eventually resolves to a list of results of each of the promises.</p>
<p>Perfect. We know the tools that we can use to chain asynchronous functions. Let’s use them in our example then:</p>
<figure>
<pre><code data-lang="r"><span>library</span><span>(</span><span>future</span><span>)</span><span>
</span><span>plan</span><span>(</span><span>multiprocess</span><span>)</span><span>
</span><span>library</span><span>(</span><span>promises</span><span>)</span><span>
</span><span>library</span><span>(</span><span>purrr</span><span>)</span><span>
</span><span>longRunningFunction</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>value</span><span>)</span><span> </span><span>{</span><span>
</span><span>Sys.sleep</span><span>(</span><span>5</span><span>)</span><span>
</span><span>return</span><span>(</span><span>value</span><span>)</span><span>
</span><span>}</span><span>
</span><span>a</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>longRunningFunction</span><span>(</span><span>1</span><span>))</span><span>
</span><span>b</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>longRunningFunction</span><span>(</span><span>2</span><span>))</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span><span> </span><span># Time: 0s
</span><span>c</span><span> </span><span>&lt;-</span><span> </span><span>future</span><span>(</span><span>longRunningFunction</span><span>(</span><span>10</span><span>))</span><span>
</span><span>a</span><span> </span><span>%...>%</span><span> </span><span>print</span><span>()</span><span>
</span><span>b</span><span> </span><span>%...>%</span><span> </span><span>print</span><span>()</span><span>
</span><span>sumAC</span><span> </span><span>&lt;-</span><span> </span><span>promise_all</span><span>(</span><span>a</span><span>,</span><span> </span><span>c</span><span>)</span><span> </span><span>%...>%</span><span> </span><span>reduce</span><span>(</span><span>`+`</span><span>)</span><span>
</span><span>sumBC</span><span> </span><span>&lt;-</span><span> </span><span>promise_all</span><span>(</span><span>b</span><span>,</span><span> </span><span>c</span><span>)</span><span> </span><span>%...>%</span><span> </span><span>reduce</span><span>(</span><span>`+`</span><span>)</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span><span> </span><span># Time: 0s
</span><span>promise_all</span><span>(</span><span>sumAC</span><span>,</span><span> </span><span>sumBC</span><span>)</span><span> </span><span>%...>%</span><span> </span><span>reduce</span><span>(</span><span>`+`</span><span>)</span><span> </span><span>%...>%</span><span> </span><span>print</span><span>()</span><span>
</span><span>print</span><span>(</span><span>&quot;User interaction&quot;</span><span>)</span><span> </span><span>#</span><span> </span><span>Time</span><span>:</span><span> </span><span>0</span><span>s</span></code></pre>
</figure>
<p>A task for you – in line <code>sumAC &lt;- promise_all(a, c) %...>% reduce(</code>+<code>)</code>, print the list of values from promises <code>a</code> and <code>c</code> before they are summed up.</p>
<p><strong>Handful of useful information:</strong></p>
<p>[1] There is support for promises implemented in shiny but neither CRAN nor GitHub master branch versions of Shiny support promises. Until support is merged, you’ll have to install from async branch:</p>
<figure>
<pre><code data-lang="r"><span>devtools</span><span>::</span><span>install_github</span><span>(</span><span>&quot;rstudio/shiny@async&quot;</span><span>)</span></code></pre>
</figure>
<p>[2] Beta-quality code at <a rel="nofollow" href="https://github.com/rstudio/promises" target="_blank">https://github.com/rstudio/promises</a></p>
<p>[3] Early drafts of docs temporarily hosted at: <a rel="nofollow" href="https://medium.com/@joe.cheng" target="_blank">https://medium.com/@joe.cheng</a></p>
<p>[4] Joe Cheng talk on EARL 2017 in London – <a rel="nofollow" href="https://www.dropbox.com/s/2gf6tfk1t345lyf/async-talk-slides.pdf?dl=0" target="_blank">https://www.dropbox.com/s/2gf6tfk1t345lyf/async-talk-slides.pdf?dl=0</a></p>
<p>[5] The plan is to release everything on CRAN by end of this year.</p>
<p><strong>I hope you have as much fun playing with the promises as I did!</strong> I’m planning to play with shiny support for promises next.</p>
<hr>
<p>Till next time!</p>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://appsilondatascience.com/blog/rstats/2017/11/01/r-promises-hands-on.html"> Appsilon Data Science Blog</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/nJev8HVpBdc" height="1"></a></div>