Requires [Qt 5.4](https://www.qt.io/download/) (or later) with [C++11 support enabled](https://wiki.qt.io/How_to_use_C++11_in_your_Qt_Projects).
## Getting Started
### Installation
QtPromise is a [header-only](https://en.wikipedia.org/wiki/Header-only) library, simply download the [latest release](https://github.com/simonbrunel/qtpromise/releases/latest) (or [`git submodule`](https://git-scm.com/docs/git-submodule])) and include `qtpromise.pri` from your project `.pro`.
Returning a `QFuture<T>` in [`then`](#qpromise-then) or [`fail`](#qpromise-fail) automatically translate to `QPromise<T>`:
```cpp
QPromise<int> input = ...
auto output = input.then([](int res) {
return QtConcurrent::run([]() {
// {...}
return QString("42");
});
});
// output type: QPromise<QString>
output.then([](const QString& res) {
// {...}
});
```
The `output` promise is resolved when the `QFuture` is [finished](http://doc.qt.io/qt-5/qfuture.html#isFinished).
### Error
Exceptions thrown from a QtConcurrent thread reject the associated promise with the exception as the reason. Note that if you throw an exception that is not a subclass of `QException`, the promise with be rejected with [`QUnhandledException`](http://doc.qt.io/qt-5/qunhandledexception.html#details) (this restriction only applies to exceptions thrown from a QtConcurrent thread, [read more](http://doc.qt.io/qt-5/qexception.html#details)).
QPromise is thread-safe and can be copied and accessed across different threads. QPromise relies on [explicitly data sharing](http://doc.qt.io/qt-5/qexplicitlyshareddatapointer.html#details) and thus `auto p2 = p1` represents the same promise: when `p1` resolves, handlers registered on `p1` and `p2` are called, the fulfilled value being shared between both instances.
> **Note:** while it's safe to access the resolved value from different threads using [`then`](#qpromise-then), QPromise provides no guarantee about the object being pointed to. Thread-safety and reentrancy rules for that object still apply.
> **Note**: only `onFulfilled` can change the promise type, `onRejected` **must** return the same type as `onFulfilled`. That also means if `onFulfilled` is `nullptr`, `onRejected` must return the same type as the `input` promise.
```cpp
QPromise<int> input = ...
auto output = input.then([](int res) {
return res + 4;
}, [](const ReasonType& reason) {
return -1;
});
```
If `onFulfilled` doesn't return any value, the `output` type is `QPromise<void>`:
```cpp
QPromise<int> input = ...
auto output = input.then([](int res) {
// {...}
});
// output type: QPromise<void>
output.then([]() {
// `QPromise<void>``onFulfilled` handler has no argument
});
```
You can also decide to skip the promise result by omitting the handler argument:
```cpp
QPromise<int> input = {...}
auto output = input.then([]( /* skip int result */ ) {
// {...}
});
```
The `output` promise can be *rejected* by throwing an exception in either `onFulfilled` or `onRejected`:
```cpp
QPromise<int> input = {...}
auto output = input.then([](int res) {
if (res == -1) {
throw ReasonType();
} else {
return res;
}
});
// output.isRejected() is true
```
If an handler returns a promise (or QFuture), the `output` promise is delayed and will be resolved by the returned promise.
This `handler` is **always** called, without any argument and whatever the `input` promise state (fulfilled or rejected). The `output` promise has the same type as the `input` one but also the same value or error. The finally `handler`**can not modify the fulfilled value** (the returned value is ignored), however, if `handler` throws, `output` is rejected with the new exception.
```cpp
auto output = input.finally([]() {
// {...}
});
```
If `handler` returns a promise (or QFuture), the `output` promise is delayed until the returned promise is resolved and under the same conditions: the delayed value is ignored, the error transmitted to the `output` promise.
This `handler` allows to observe the value of the `input` promise, without changing the propagated value. The `output` promise will be resolved with the same value as the `input` promise (the `handler` returned value will be ignored). However, if `handler` throws, `output` is rejected with the new exception. Unlike [`finally`](#qpromise-finally), this handler is **not** called for rejections.
If `handler` returns a promise (or QFuture), the `output` promise is delayed until the returned promise is resolved and under the same conditions: the delayed value is ignored, the error transmitted to the `output` promise.
This method returns a promise that will be fulfilled with the same value as the `input` promise and after at least `msec` milliseconds. If the `input` promise is rejected, the `output` promise is immediately rejected with the same reason.
```cpp
QPromise<int> input = {...}
auto output = input.delay(2000).then([](int res) {
Returns a `QPromise<QVector<T>>` that fulfills when **all**`promises` of (the same) type `T` have been fulfilled. The `output` value is a vector containing **all** the values of `promises`, in the same order. If any of the given `promises` fail, `output` immediately rejects with the error of the promise that rejected, whether or not the other promises are resolved.
```cpp
QVector<QPromise<QByteArray> > promises{
download(QUrl("http://a...")),
download(QUrl("http://b...")),
download(QUrl("http://c..."))
};
auto output = QPromise<QByteArray>::all(promises);
This method simply calls the appropriated [`QPromise<T>::all`](#qpromise-all) static method based on the given `QVector` type. In some cases, this method is more convenient than the static one since it avoid some extra typing: