<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Uasync on Huy Minh Ha</title><link>https://minhhh.github.io/tags/uasync/</link><description>Recent content in Uasync on Huy Minh Ha</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Mon, 08 May 2017 00:00:00 +0700</lastBuildDate><atom:link href="https://minhhh.github.io/tags/uasync/index.xml" rel="self" type="application/rss+xml"/><item><title>Introducing UAsync</title><link>https://minhhh.github.io/posts/uasync/</link><pubDate>Mon, 08 May 2017 00:00:00 +0700</pubDate><guid>https://minhhh.github.io/posts/uasync/</guid><description>&lt;p&gt;Nowadays, if you want to use a structured way for your flow control in Unity, you basically have 4 options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write your own &lt;code&gt;Task&lt;/code&gt; library (which might use coroutines)&lt;/li&gt;
&lt;li&gt;Use coroutines. This means that you &lt;code&gt;StartCoroutine&lt;/code&gt; in a lot of places and insert try catch code when errors occur. This works for small games. For larger games, not being able to catch nested exception is a big NO NO.&lt;/li&gt;
&lt;li&gt;Use &lt;a class="link" href="https://github.com/Real-Serious-Games/C-Sharp-Promise" target="_blank" rel="noopener"
 &gt;C-Sharp-Promise&lt;/a&gt;. If you&amp;rsquo;re familiar with JS promises, this comes natural to you. It handles exceptions pretty well. You can try combining this with coroutine, but the API is probably verbose.&lt;/li&gt;
&lt;li&gt;Use &lt;a class="link" href="https://github.com/neuecc/UniRx" target="_blank" rel="noopener"
 &gt;UniRx&lt;/a&gt;. This is simply the best choice because it supports control flow, exception handling, progress report and coroutine.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So we should always use &lt;code&gt;UniRx&lt;/code&gt;, right? Unfortunately, sometimes the efforts to use &lt;code&gt;UniRx&lt;/code&gt; is just too much that we can&amp;rsquo;t afford. In that case, it&amp;rsquo;s better to use existing solution, but with more robust code. (&lt;code&gt;C-Sharp-Promise&lt;/code&gt; is ofcourse another option, but it is not compatible with coroutine and existing coroutine code without some custom modifications).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;UAsync&lt;/code&gt; &lt;a class="link" href="https://github.com/minhhh/UAsync" target="_blank" rel="noopener"
 &gt;Unity Async&lt;/a&gt; is a library that helps you write Unity code using callback style of &lt;code&gt;Node.js&lt;/code&gt; and &lt;code&gt;async&lt;/code&gt; library. The &lt;code&gt;TaskRunner&lt;/code&gt; part is taken from &lt;a class="link" href="https://github.com/sebas77/Svelto.Tasks" target="_blank" rel="noopener"
 &gt;Svelto.Tasks&lt;/a&gt; with some modifications to make it support catching exceptions and returning errors. The &lt;code&gt;UAsync&lt;/code&gt; class adds several functions on top of &lt;code&gt;TaskRunner&lt;/code&gt; to support execution of tasks in parallel or serial with returned results at the end of the execution. For the moment, it does not support &lt;code&gt;Thread&lt;/code&gt; because it focuses on control flow, not enhancing performance by distributing work to multiple cores.&lt;/p&gt;
&lt;p&gt;To include UAsync into your project, you can use &lt;code&gt;npm&lt;/code&gt; method of unity package management described &lt;a class="link" href="https://github.com/minhhh/UBootstrap" target="_blank" rel="noopener"
 &gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="usage"&gt;Usage
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;TaskRunner&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First of all, it&amp;rsquo;s quite well-known that 2 main disadvantages of coroutine are: 1) it cannot return value and 2) it cannot handle nested exception. There&amp;rsquo;s a simple way to wrap coroutine so we can support those 2 features, as detailed in &lt;a class="link" href="http://www.zingweb.com/blog/2013/02/05/unity-coroutine-wrapper" target="_blank" rel="noopener"
 &gt;this article&lt;/a&gt;. &lt;code&gt;TaskRunner&lt;/code&gt; also supports returning value and catching exceptions using callback style. You use it like so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;using UAsync;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;TaskRunner.Instance.Run (task, onComplete);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// public TaskRoutine Run (IEnumerator task, CallbackDelegate onComplete = null)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;In the code above, &lt;code&gt;task&lt;/code&gt; is a &lt;code&gt;IEnumerator&lt;/code&gt; and &lt;code&gt;onComplete&lt;/code&gt; is a delegate of type &lt;code&gt;CallbackDelegate (object err = null, object res = null)&lt;/code&gt;. Any exceptions occur will be passed via &lt;code&gt;err&lt;/code&gt;. The last &lt;code&gt;yield&lt;/code&gt; in &lt;code&gt;task&lt;/code&gt; will be passed to &lt;code&gt;res&lt;/code&gt;. You might want to use &lt;code&gt;TaskRunner.Instance.Run&lt;/code&gt; when you have a sequence of actions to be performed in a fixed order.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UAsync&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;UAsync&lt;/code&gt; is a port of Node&amp;rsquo;s &lt;code&gt;async&lt;/code&gt; module to Unity environment. It can be used to turn a set of synchronous functions or coroutine to run sequentially or concurrently. Even though you can already run a set of tasks sequentially using coroutine, passing values between these tasks are proven to be difficult. You have to use external variables to hold the return values which creates coupling between functions, and it&amp;rsquo;s not convenient. &lt;code&gt;UAsync&lt;/code&gt; can solve this problem by allowing coroutine to return value, as well as catching exceptions if any.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;series&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UAsync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Async&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Series&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;SeriesFunc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromAction&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;one&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SeriesFunc1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;SeriesFunc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromEnumerator&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;two&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SeriesFunc2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;SeriesFunc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromAction&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;three&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SeriesFunc3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UAsyncFinalFunc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;From&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ne"&gt;Dictionary&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Finish &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;res &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;one&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;two&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34; &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;three&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;SeriesFunc1&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CallbackDelegate&lt;/span&gt; &lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ne"&gt;Dictionary&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cb&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;IEnumerator&lt;/span&gt; &lt;span class="n"&gt;SeriesFunc2&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CallbackDelegate&lt;/span&gt; &lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ne"&gt;Dictionary&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;WaitForSeconds&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cb&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;SeriesFunc3&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CallbackDelegate&lt;/span&gt; &lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ne"&gt;Dictionary&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cb&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Here, &lt;code&gt;SeriesFunc.FromAction&lt;/code&gt; and &lt;code&gt;SeriesFunc.FromEnumerator&lt;/code&gt; are just convenient functions to wrap synchronous functions and coroutines. Each of the functions &lt;code&gt;SeriesFunc1&lt;/code&gt;, &lt;code&gt;SeriesFunc2&lt;/code&gt; and &lt;code&gt;SeriesFunc3&lt;/code&gt; will receive a callback parameter and a &lt;code&gt;res&lt;/code&gt; parameter. To complete the execution of each function, you must call &lt;code&gt;cb&lt;/code&gt; with 2 parameters: &lt;code&gt;err&lt;/code&gt; representing the error, and &lt;code&gt;result&lt;/code&gt; representing the returned value. In the code above, there is no error. If any of the code in those function throws exception, cb will also be called automatically with the exception as the first parameter.&lt;/p&gt;
&lt;p&gt;The second parameter passed to each of the functions &lt;code&gt;SeriesFunc1&lt;/code&gt;, &lt;code&gt;SeriesFunc2&lt;/code&gt; and &lt;code&gt;SeriesFunc3&lt;/code&gt; is quite important. It is a dicionary which contains all the results from previous functions, so &lt;code&gt;SeriesFunc2&lt;/code&gt; will receive result from &lt;code&gt;SeriesFunc1&lt;/code&gt;, &lt;code&gt;SeriesFunc3&lt;/code&gt; will receive results from &lt;code&gt;SeriesFunc1&lt;/code&gt; and &lt;code&gt;SeriesFunc2&lt;/code&gt;. The key of the dictionary are declared when creating the series, e.g. SeriesFunc.FromAction (&amp;ldquo;one&amp;rdquo;, SeriesFunc1) means the result of SeriesFunc1 will have key &amp;ldquo;one&amp;rdquo;. This is a powerful way to pass results between functions without creating high coupling between them.&lt;/p&gt;
&lt;p&gt;After all the functions have been executed, there is a final function &lt;code&gt;UAsyncFinalFunc&lt;/code&gt; which will receive all the results and execute some logic accordingly. If any of the functions above throws exceptions or calls callback with a &lt;code&gt;err&lt;/code&gt; parameter, the error will be passed to the final function to deal with.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;UAsync.Async.Parallel&lt;/code&gt; function is similar to the &lt;code&gt;Series&lt;/code&gt; function, except that there will be no results from previous functions since they&amp;rsquo;re executed concurrently.&lt;/p&gt;
&lt;p&gt;Finally, you can cancel a running sequence once it&amp;rsquo;s started. This is not obvious with coroutine because even though you can call &lt;code&gt;MonoBehaviour.StopCoroutine&lt;/code&gt;&lt;/p&gt;</description></item></channel></rss>