Implement QPromise::delay(msec)

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.
This commit is contained in:
Simon Brunel 2017-08-24 18:28:44 +02:00
parent c55fa03e7b
commit b47ca0569e
4 changed files with 60 additions and 0 deletions

View File

@ -304,6 +304,7 @@ If `handler` returns a promise (or QFuture), the `output` promise is delayed unt
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. 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.
```cpp ```cpp
QPromise<int> input = {...}
auto output = input.tap([](int res) { auto output = input.tap([](int res) {
log(res); log(res);
}).then([](int res) { }).then([](int res) {
@ -313,6 +314,16 @@ auto output = input.tap([](int res) {
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. 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.
### <a name="qpromise-delay"></a> `QPromise<T>::delay(handler) -> QPromise<T>`
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) {
// called 2 seconds after `input` is fulfilled
});
```
### <a name="qpromise-wait"></a> `QPromise<T>::wait() -> QPromise<T>` ### <a name="qpromise-wait"></a> `QPromise<T>::wait() -> QPromise<T>`
This method holds the execution of the remaining code **without** blocking the event loop of the current thread: This method holds the execution of the remaining code **without** blocking the event loop of the current thread:

View File

@ -46,6 +46,7 @@ public:
template <typename THandler> template <typename THandler>
inline QPromise<T> tap(THandler handler) const; inline QPromise<T> tap(THandler handler) const;
inline QPromise<T> delay(int msec) const;
inline QPromise<T> wait() const; inline QPromise<T> wait() const;
void swap(QPromiseBase<T>& other) { qSwap(m_d, other.m_d); } void swap(QPromiseBase<T>& other) { qSwap(m_d, other.m_d); }

View File

@ -1,6 +1,7 @@
// Qt // Qt
#include <QCoreApplication> #include <QCoreApplication>
#include <QSharedPointer> #include <QSharedPointer>
#include <QTimer>
namespace QtPromise { namespace QtPromise {
@ -149,6 +150,16 @@ inline QPromise<T> QPromiseBase<T>::tap(THandler handler) const
}); });
} }
template <typename T>
inline QPromise<T> QPromiseBase<T>::delay(int msec) const
{
return tap([=]() {
return QPromise<void>([&](const QPromiseResolve<void>& resolve) {
QTimer::singleShot(msec, resolve);
});
});
}
template <typename T> template <typename T>
inline QPromise<T> QPromiseBase<T>::wait() const inline QPromise<T> QPromiseBase<T>::wait() const
{ {

View File

@ -3,6 +3,7 @@
// Qt // Qt
#include <QtTest> #include <QtTest>
#include <QElapsedTimer>
using namespace QtPromise; using namespace QtPromise;
using namespace QtPromisePrivate; using namespace QtPromisePrivate;
@ -48,6 +49,9 @@ private Q_SLOTS:
void tapDelayedResolved(); void tapDelayedResolved();
void tapDelayedRejected(); void tapDelayedRejected();
void delayFulfilled();
void delayRejected();
}; // class tst_qpromise }; // class tst_qpromise
QTEST_MAIN(tst_qpromise) QTEST_MAIN(tst_qpromise)
@ -654,3 +658,36 @@ void tst_qpromise::tapDelayedRejected()
QCOMPARE(p.isRejected(), true); QCOMPARE(p.isRejected(), true);
QCOMPARE(values, QVector<int>({2, 3})); QCOMPARE(values, QVector<int>({2, 3}));
} }
void tst_qpromise::delayFulfilled()
{
QElapsedTimer timer;
qint64 elapsed = -1;
timer.start();
auto p = QPromise<int>::resolve(42).delay(1000).finally([&]() {
elapsed = timer.elapsed();
});
QCOMPARE(waitForValue(p, -1), 42);
QCOMPARE(p.isFulfilled(), true);
QVERIFY(elapsed >= 1000 * 0.95); // Qt::CoarseTimer (default) Coarse timers try to
QVERIFY(elapsed <= 1000 * 1.05); // keep accuracy within 5% of the desired interval.
}
void tst_qpromise::delayRejected()
{
QElapsedTimer timer;
qint64 elapsed = -1;
timer.start();
auto p = QPromise<int>::reject(QString("foo")).delay(1000).finally([&]() {
elapsed = timer.elapsed();
});
QCOMPARE(waitForError(p, QString()), QString("foo"));
QCOMPARE(p.isRejected(), true);
QVERIFY(elapsed < 5);
}