<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[AsyncFuture - Use QFuture like a Promise object]]></title><description><![CDATA[<p dir="auto">Hello,</p>
<p dir="auto">I would like to share my latest project here. That is <a href="https://github.com/benlau/asyncfuture/" target="_blank" rel="noopener noreferrer nofollow ugc">AsyncFuture</a>. That make you able to use QFuture like a Promise Object in Javascript.</p>
<p dir="auto">Project Site:<br />
<a href="https://github.com/benlau/asyncfuture" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/benlau/asyncfuture</a></p>
<h2>AsyncFuture - Use QFuture like a Promise object</h2>
<p dir="auto">QFuture represents the result of an asynchronous computation. It is a powerful component for multi-thread programming. But its usage is limited to the result of threads. And QtConcurrent only provides a MapReduce usage model that may not fit your usage. Morever, it doesn't work with the asynchronous signal emitted by QObject. And it is a bit trouble to setup the listener function via QFutureWatcher.</p>
<p dir="auto">AsyncFuture is designed to enhance the function to offer a better way to use it for asynchronous programming.  It provides a Promise object like interface. This project is inspired by AsynQt and RxCpp.</p>
<p dir="auto">Remarks: You may use this project together with <a href="https://github.com/benlau/quickfuture" target="_blank" rel="noopener noreferrer nofollow ugc">QuickFuture</a> for QML programming.</p>
<h1>Features</h1>
<p dir="auto"><strong>1. Convert a signal from QObject into a QFuture object</strong></p>
<pre><code class="language-c++">
#include "asyncfuture.h"
using namespace AsyncFuture;

// Convert a signal from QObject into a QFuture object

QFuture&lt;void&gt; future = observe(timer,
                               &amp;QTimer::timeout).future();

/* Listen from the future without using QFutureWatcher&lt;T&gt;*/
observe(future).subscribe([]() {
    // onCompleted. It is invoked when the observed future is finished successfully
    qDebug() &lt;&lt; "onCompleted";
},[]() {
    // onCanceled
    qDebug() &lt;&lt; "onCancel";
});

/* It is chainable. Listen from a timeout signal only once */
observe(timer, &amp;QTimer::timeout).subscribe([=]() { /*…*/ });
</code></pre>
<p dir="auto"><strong>2. Combine multiple futures with different type into a single future object</strong></p>
<pre><code class="language-c++">/* Combine multiple futures with different type into a single future */

QFuture&lt;QImage&gt; f1 = QtConcurrent::run(readImage, QString("image.jpg"));

QFuture&lt;void&gt; f2 = observe(timer, &amp;QTimer::timeout).future();

(combine() &lt;&lt; f1 &lt;&lt; f2).subscribe([](QVariantList result){
    // Read an image
    // result[0] = QImage
    qDebug() &lt;&lt; result;
});
</code></pre>
<p dir="auto"><strong>3. Advanced multi-threading model</strong></p>
<pre><code class="language-c++">/* Start a thread and process its result in main thread */

QFuture&lt;QImage&gt; reading = QtConcurrent::run(readImage, QString("image.jpg"));

QFuture&lt;bool&gt; validating = observe(reading).context(contextObject, validator).future();

    // Read image by a thread, when it is ready, run the validator function
    // in the thread of the contextObject(e.g main thread)
    // And it return another QFuture to represent the final result.

/* Start a thread and process its result in main thread, then start another thread. */

QFuture&lt;int&gt; f1 = QtConcurrent::mapped(input, mapFunc);

QFuture&lt;int&gt; f2 = observe(f1).context(contextObject, [=](QFuture&lt;int&gt; future) {
    // You may use QFuture as the input argument of your callback function
    // It will be set to the observed future object. So that you may obtain
    // the value of results()

    qDebug() &lt;&lt; future.results();

    // Return another QFuture is possible.
    return QtConcurrent::run(reducerFunc, future.results());
}).future();

// f2 is constructed before the QtConcurrent::run statement
// But its value is equal to the result of reducerFunc

</code></pre>
<p dir="auto"><strong>4. Promise like interface</strong></p>
<p dir="auto">The deferred&lt;T&gt;() function return a Deferred&lt;T&gt; object that allows you to manipulate a QFuture manually. The future() function return a forever running QFuture&lt;T&gt; unless you have called Deferred.complete() / Deferred.cancel() manually, or the Deferred object is destroyed without observed any future.</p>
<p dir="auto">The usage of complete/cancel with a Deferred object is pretty similar to the resolve/reject in a Promise object. You could complete a future by calling complete with a result value. If you give it another future, then it will observe the input future and change status once that is finished.</p>
<p dir="auto">Complete / cancel a future on your own choice</p>
<pre><code class="language-c++">// Complete / cancel a future on your own choice
auto d = deferred&lt;bool&gt;();

observe(d.future()).subscribe([]() {
    qDebug() &lt;&lt; "onCompleted";
}, []() {
    qDebug() &lt;&lt; "onCancel";
});

d.complete(true); // or d.cancel();

QCOMPARE(d.future().isFinished(), true);
QCOMPARE(d.future().isCanceled(), false);

</code></pre>
<p dir="auto">Complete / cancel a future according to another future object.</p>
<pre><code class="language-c++">// Complete / cancel a future according to another future object.

auto d = deferred&lt;void&gt;();

d.complete(QtConcurrent::run(timeout));

QCOMPARE(d.future().isFinished(), true);
QCOMPARE(d.future().isCanceled(), false);

</code></pre>
<p dir="auto">Read a file. If timeout, cancel it.</p>
<pre><code class="language-c++">
auto timeout = observe(timer, &amp;QTimer::timeout).future();

auto defer = deferred&lt;QString&gt;();

defer.complete(QtConcurrent::run(readFileworker, fileName));
defer.cancel(timeout);

return defer.future();
</code></pre>
<p dir="auto">More examples are available at : <a href="https://github.com/benlau/asyncfuture/blob/master/tests/asyncfutureunittests/example.cpp" target="_blank" rel="noopener noreferrer nofollow ugc">asyncfuture/example.cpp at master · benlau/asyncfuture</a></p>
<h1>Installation</h1>
<p dir="auto">AsyncFuture is a single header library. You could just download the <code>asyncfuture.h</code> in your source tree or install it via qpm</p>
<pre><code>qpm install async.future.pri
</code></pre>
<p dir="auto">or</p>
<pre><code>wget https://raw.githubusercontent.com/benlau/asyncfuture/master/asyncfuture.h
</code></pre>
]]></description><link>https://forum.qt.io/topic/77378/asyncfuture-use-qfuture-like-a-promise-object</link><generator>RSS for Node</generator><lastBuildDate>Wed, 22 Apr 2026 09:09:18 GMT</lastBuildDate><atom:link href="https://forum.qt.io/topic/77378.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 20 Mar 2017 05:55:57 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to AsyncFuture - Use QFuture like a Promise object on Fri, 05 Jan 2018 08:47:52 GMT]]></title><description><![CDATA[<p dir="auto">In order to let users to get started easily, I have started to write a series of article about different use-case and how AsyncFuture could help to reduce the workload. The first one is ready:</p>
<p dir="auto"><a href="https://medium.com/e-fever/asyncfuture-cookbook-1-calling-qtconcurrent-mapped-within-the-run-function-ba58d523a0ce" target="_blank" rel="noopener noreferrer nofollow ugc">AsyncFuture Cookbook 1 — Calling QtConcurrent::mapped within the run function</a></p>
]]></description><link>https://forum.qt.io/post/434862</link><guid isPermaLink="true">https://forum.qt.io/post/434862</guid><dc:creator><![CDATA[benlau]]></dc:creator><pubDate>Fri, 05 Jan 2018 08:47:52 GMT</pubDate></item><item><title><![CDATA[Reply to AsyncFuture - Use QFuture like a Promise object on Thu, 28 Dec 2017 14:35:42 GMT]]></title><description><![CDATA[<p dir="auto">Merry Christmas and Happy new year!!</p>
<p dir="auto">A late Christmas gift - The v0.4 version of AsyncFuture has been released.</p>
<h1>AsyncFuture 0.4 Release Notes</h1>
<h1>New Features</h1>
<p dir="auto"><em>1) Improved Compilation Error Message on invalid callback</em></p>
<p dir="auto">The compilation error related to the template in C++ is known to be giant and misleading. It is prioritized to inform you where the error occurs in the template declaration, which is not written by you and you have no knowledge about the implementation.</p>
<p dir="auto">AsyncFuture v0.4 inserted many static_asserts in the subscribe()/context() to capture error in the early stage.  It could reduce the no. of error messages and tell users what is wrong actually in their code.</p>
<p dir="auto">Error Messages:</p>
<ol>
<li>Observe a QFuture&lt;void&gt; but your callback contains an input argument</li>
<li>Callback function should not take more than 1 argument</li>
<li>The callback function is not callable. The input argument doesn't match with the observing QFuture type</li>
</ol>
<p dir="auto"><em>2) Future Object Tracking - The advanced usage with QtConcurrent::mapped</em></p>
<p dir="auto">The deferred object is now supported to track the status of another future object. It will synchronize the <code>progressValue</code> / <code>progressMinimium </code> /  <code>progressMaximium</code> and status of the tracking object. (e.g started signal)</p>
<p dir="auto">For example:</p>
<pre><code class="language-c++">
        auto defer = AsyncFuture::deferred&lt;QImage&gt;();

        QFuture&lt;QImage&gt; mapped = QtConcurrent::mapped(files, readImage);

        defer.complete(mapped); // defer.future() will be a mirror of `mapped`. The `progressValue` will be changed and it will emit "started" signal via QFutureWatcher

</code></pre>
<p dir="auto">A practical use-case</p>
<pre><code class="language-c++">
QFuture&lt;QImage&gt; readImagesFromFolder(const QString&amp; folder) {

    auto worker = [=]() {
        // Read files from a directory in a thread
        QStringList files = findImageFiles(folder);

        // Concurrent image reader
        return QtConcurrent::mapped(files, readImage);
    };

    auto future = QtConcurrent::run(worker); // The type of future is QFuture&lt;QFuture&lt;QImage&gt;&gt;

    auto defer = AsyncFuture::deferred&lt;QImage&gt;();

    // defer object track the input future. It will emit "started" and `progressValueChanged` according to the status of the future of "QtConcurrent::mapped"
    defer.complete(future);
    return defer.future();
}
</code></pre>
<p dir="auto">In the example code above, the future returned by <code>defer.future()</code> is supposed to be a mirror of the result of <code>QtConcurrent::mapped</code>. However, the linkage is  not estimated in the beginning until the worker functions start <code>QtConcurrent::mapped</code></p>
<p dir="auto">In case it needs to track the status of a future object but it won’t complete automatically. It may use track() function</p>
<p dir="auto"><em>3) Support mutable lambda function</em></p>
<p dir="auto">In AsyncFuture 0.3, the following is invalid because the deferred object is marked as const</p>
<pre><code class="language-c++">auto defer = AsyncFuture::deferred&lt;void&gt;();
QtConcurrent::run([=]() {
  defer.complete(); // Compilation error
});
</code></pre>
<p dir="auto">Mutable lambda function is supported in v4.0, so it could be solved by marking the lambda function as mutable:</p>
<pre><code class="language-c++">auto defer = AsyncFuture::deferred&lt;void&gt;();
QtConcurrent::run([=]() mutable {
  defer.complete();  
});
</code></pre>
<h1>New API</h1>
<p dir="auto"><strong>AsyncFuture::observe(QFuture&lt;QFuture&lt;T&gt;&gt; future)</strong></p>
<p dir="auto">This function creates an <code>Observable&lt;T&gt;</code> object which provides an interface for observing the input future.  That is designed to handle the following use-case:</p>
<pre><code>QFuture&lt;QImage&gt; readImagesFromFolder(const QString&amp; folder) {

    auto worker = [=]() {
        // Read files from a directory in a thread
        QStringList files = findImageFiles(folder);

        // Concurrent image reader
        return QtConcurrent::mapped(files, readImage);
    };

    auto future = QtConcurrent::run(worker); // The type of future is QFuture&lt;QFuture&lt;QImage&gt;&gt;

    auto defer = AsyncFuture::deferred&lt;QImage&gt;();

    // defer object track the input future. It will emit "started" and `progressValueChanged` according to the status of the future of "QtConcurrent::mapped"
    defer.complete(future);
    return defer.future();
}
</code></pre>
<p dir="auto">See <a href="#observablet">Observable<code>&lt;T&gt;</code></a></p>
<p dir="auto"><strong>AsyncFuture::observe(object, SIGNAL(signal))</strong></p>
<p dir="auto">This function creates an <code>Observable&lt;QVariant&gt;</code> object which contains a future to represent the result of the signal. You could obtain the future by the future() method. And observe the result by subscribe() / context() methods. The result of the future is equal to the first parameter of the signal.</p>
<pre><code class="language-c++">QFuture&lt;QVariant&gt; future = observe(timer, SIGNAL(timeout()).future();
</code></pre>
<p dir="auto">See <a href="#observablet">Observable<code>&lt;T&gt;</code></a></p>
<p dir="auto">Added since v0.4</p>
<p dir="auto"><strong>Observable::onProgress(callback)</strong></p>
<p dir="auto">Listens the <code>progressValueChanged</code> and <code>progressRangeChanged</code> signal from the observed future then trigger the callback. The callback function may return nothing or a boolean value. If the boolean value is false, it will remove the listener such that the callback may not trigger anymore.</p>
<p dir="auto">Example</p>
<pre><code class="language-c++">QFuture&lt;int&gt; future = QtConcurrent::mapped(input, workerFunction);

AsyncFuture::observe(future).onProgress([=]() -&gt; bool {
    qDebug() &lt;&lt; future.progressValue();
    return true;
});

// or

AsyncFuture::observe(future).onProgress([=]() -&gt; void {
    qDebug() &lt;&lt; future.progressValue();
});
</code></pre>
<p dir="auto"><strong>Deferred::track(future)</strong></p>
<p dir="auto">Track the progress and synchronize the status of the target future object.</p>
<p dir="auto">It will forward the signal of <code>started</code> , <code>resumed</code> , <code>paused</code> . And synchonize  the <code>progressValue</code>, <code>progressMinimum</code> and <code>progressMaximum</code> value by listening the  <code>progressValueChanged</code> signal from target future object.</p>
<p dir="auto">Remarks: It won't complete a future even the <code>progressValue</code> has been reached the maximum value.</p>
<p dir="auto"><strong>Deferred&lt;T&gt;::complete(QList&lt;T&gt;)</strong></p>
<p dir="auto">Complete the future object with a list of result. A user may obtain all the value by QFuture::results().</p>
<h1>API Changes</h1>
<p dir="auto"><strong>Deferred::complete(<code>QFuture&lt;T&gt;</code> target)</strong></p>
<p dir="auto">Complete the deferred according to the target future. It will also track the <code>progressValue</code> and status.</p>
<p dir="auto"><strong>AsyncFuture::combine()</strong></p>
<p dir="auto">Supported to combine deferred object</p>
<pre><code class="language-c++">Observable&lt;void&gt; o;
auto all = combine() &lt;&lt; o;
</code></pre>
]]></description><link>https://forum.qt.io/post/433844</link><guid isPermaLink="true">https://forum.qt.io/post/433844</guid><dc:creator><![CDATA[benlau]]></dc:creator><pubDate>Thu, 28 Dec 2017 14:35:42 GMT</pubDate></item><item><title><![CDATA[Reply to AsyncFuture - Use QFuture like a Promise object on Mon, 02 Oct 2017 03:47:20 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/tekojo">@<bdi>tekojo</bdi></a> Should be a good idea. I think I may add a page about how to capture a signal by QFuture / Use QFuture to handle asynchronous signal.</p>
]]></description><link>https://forum.qt.io/post/384071</link><guid isPermaLink="true">https://forum.qt.io/post/384071</guid><dc:creator><![CDATA[benlau]]></dc:creator><pubDate>Mon, 02 Oct 2017 03:47:20 GMT</pubDate></item><item><title><![CDATA[Reply to AsyncFuture - Use QFuture like a Promise object on Wed, 22 Mar 2017 14:22:39 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/benlau">@<bdi>benlau</bdi></a> pretty much. You already have more content in this post :)</p>
]]></description><link>https://forum.qt.io/post/383527</link><guid isPermaLink="true">https://forum.qt.io/post/383527</guid><dc:creator><![CDATA[tekojo]]></dc:creator><pubDate>Wed, 22 Mar 2017 14:22:39 GMT</pubDate></item><item><title><![CDATA[Reply to AsyncFuture - Use QFuture like a Promise object on Tue, 21 Mar 2017 16:51:54 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/tekojo">@<bdi>tekojo</bdi></a> said in <a href="/post/382982">AsyncFuture - Use QFuture like a Promise object</a>:</p>
<blockquote>
<p dir="auto">Thanks <a class="plugin-mentions-user plugin-mentions-a" href="/user/benlau">@<bdi>benlau</bdi></a> !</p>
<p dir="auto">Would there be a chance of adding this to the <a href="https://wiki.qt.io/Main" target="_blank" rel="noopener noreferrer nofollow ugc">Qt wiki</a> too?<br />
There it would be more permanent, the content here in the forums flows into history fast.</p>
</blockquote>
<p dir="auto">Like this kind of page?</p>
<p dir="auto"><a href="https://wiki.qt.io/QtConcurrent-run-inherited-member-function" target="_blank" rel="noopener noreferrer nofollow ugc">https://wiki.qt.io/QtConcurrent-run-inherited-member-function</a></p>
]]></description><link>https://forum.qt.io/post/383351</link><guid isPermaLink="true">https://forum.qt.io/post/383351</guid><dc:creator><![CDATA[benlau]]></dc:creator><pubDate>Tue, 21 Mar 2017 16:51:54 GMT</pubDate></item><item><title><![CDATA[Reply to AsyncFuture - Use QFuture like a Promise object on Mon, 20 Mar 2017 08:39:32 GMT]]></title><description><![CDATA[<p dir="auto">Thanks <a class="plugin-mentions-user plugin-mentions-a" href="/user/benlau">@<bdi>benlau</bdi></a> !</p>
<p dir="auto">Would there be a chance of adding this to the <a href="https://wiki.qt.io/Main" target="_blank" rel="noopener noreferrer nofollow ugc">Qt wiki</a> too?<br />
There it would be more permanent, the content here in the forums flows into history fast.</p>
]]></description><link>https://forum.qt.io/post/382982</link><guid isPermaLink="true">https://forum.qt.io/post/382982</guid><dc:creator><![CDATA[tekojo]]></dc:creator><pubDate>Mon, 20 Mar 2017 08:39:32 GMT</pubDate></item><item><title><![CDATA[Reply to AsyncFuture - Use QFuture like a Promise object on Mon, 20 Mar 2017 08:11:01 GMT]]></title><description><![CDATA[<p dir="auto">Hi,</p>
<p dir="auto">Looks nice, thanks for sharing !</p>
]]></description><link>https://forum.qt.io/post/382972</link><guid isPermaLink="true">https://forum.qt.io/post/382972</guid><dc:creator><![CDATA[SGaist]]></dc:creator><pubDate>Mon, 20 Mar 2017 08:11:01 GMT</pubDate></item></channel></rss>