Promise then:, asyncThen:, and then:otherwise: usage
Basic
TAsyncPromise
Trait named: #TAsyncPromise
instanceVariableNames: ''
package: 'Futures-Base - Promises'
returns computed value:
And may hold a rejected value (error):
Then: usage
The TAsyncPromise>>#then:
then: onFulfilledBlock
"If the original promise already has a computed value, the onFulfilledBlock block
is computed in a current process. If the promise does not have the value,
the onFulfilledBlock block is computed later in another process.
Notice that onFulfilledBlock is computed only on success promise values.
If you need handle also failures (rejected values), consider using #then:otherwise:.
If you want to guarantee that the current process is never blocked (e.g.,
due to an expensive onFulfilledBlock computation), consider using #asyncThen:"
<return: #TAsyncPromise>
^ self explicitRequirement
is executed on success value:
[ 1 / 4 ] asAsyncPromise then: [ :n | n * 2 ]
If the promise value is already computed, #selector
then: onFulfilledBlock
"If the original promise already has a computed value, the onFulfilledBlock block
is computed in a current process. If the promise does not have the value,
the onFulfilledBlock block is computed later in another process.
Notice that onFulfilledBlock is computed only on success promise values.
If you need handle also failures (rejected values), consider using #then:otherwise:.
If you want to guarantee that the current process is never blocked (e.g.,
due to an expensive onFulfilledBlock computation), consider using #asyncThen:"
<return: #TAsyncPromise>
^ self explicitRequirement
is computed immediatelly:
aPromise := [ 1 / 4 ] asAsyncPromise.
aPromise wait.
aPromise then: [ :n |
"Block computation for a two seconds"
2 seconds wait.
n * 2 ]
We therefore advice you to use #selector
then: onFulfilledBlock
"If the original promise already has a computed value, the onFulfilledBlock block
is computed in a current process. If the promise does not have the value,
the onFulfilledBlock block is computed later in another process.
Notice that onFulfilledBlock is computed only on success promise values.
If you need handle also failures (rejected values), consider using #then:otherwise:.
If you want to guarantee that the current process is never blocked (e.g.,
due to an expensive onFulfilledBlock computation), consider using #asyncThen:"
<return: #TAsyncPromise>
^ self explicitRequirement
only when you do not mind to have a blocking computation. For other cases, you can use #selector
asyncThen: onFulfilledBlock
"Compared to the #then: method, I guarantee that the onFulfilledBlock block
is executed asynchronously even if the original promise already has a value.
It implies that onFulfilledBlock computation does not block a current process."
<return: #TAsyncPromise>
^ self explicitRequirement
as explained later.
The #selector
then: onFulfilledBlock
"If the original promise already has a computed value, the onFulfilledBlock block
is computed in a current process. If the promise does not have the value,
the onFulfilledBlock block is computed later in another process.
Notice that onFulfilledBlock is computed only on success promise values.
If you need handle also failures (rejected values), consider using #then:otherwise:.
If you want to guarantee that the current process is never blocked (e.g.,
due to an expensive onFulfilledBlock computation), consider using #asyncThen:"
<return: #TAsyncPromise>
^ self explicitRequirement
block is not executed on a failure, for that reason you will see
Waiting a promise value
forever when you play and inspect the following snippet:
[ 1 / 0 ] asAsyncPromise then: [ :n | n * 2 ]
If you need to handle failures, you can use #selector
then: onFulfilledBlock otherwise: onRejectedBlock
"Compared to the #then: method, I handle an otherwise (error) case too.
Consider to return a 'sensible' onRejectedBlock value, which is usually
of the same type as the onFulfilledBlock return value. For example:
[ 1 / 0 ] asAsyncPromise then: [ :n | n * 2 ] otherwise: [ :e | 0 ]"
<return: #TAsyncPromise>
^ self explicitRequirement
[ 1 / 0 ] asAsyncPromise
then: [ :n | n * 2 ]
otherwise: [ :e | 0 ]
Notice, that #selector
then: onFulfilledBlock otherwise: onRejectedBlock
"Compared to the #then: method, I handle an otherwise (error) case too.
Consider to return a 'sensible' onRejectedBlock value, which is usually
of the same type as the onFulfilledBlock return value. For example:
[ 1 / 0 ] asAsyncPromise then: [ :n | n * 2 ] otherwise: [ :e | 0 ]"
<return: #TAsyncPromise>
^ self explicitRequirement
is also blocking in case of already computed value:
aPromise := [ 1 / 0 ] asAsyncPromise.
[ aPromise wait ] on: Error do: [ :e | "ignore" ].
aPromise
then: [ :n |
n * 2 ]
otherwise: [ :e |
"Block computation for a two seconds"
2 seconds wait.
0 ]
AsyncThen: usage
#selector
asyncThen: onFulfilledBlock
"Compared to the #then: method, I guarantee that the onFulfilledBlock block
is executed asynchronously even if the original promise already has a value.
It implies that onFulfilledBlock computation does not block a current process."
<return: #TAsyncPromise>
^ self explicitRequirement
never block execution. Compare:
aPromise := [ 1 / 4 ] asAsyncPromise.
aPromise wait.
aPromise
then: [ :n |
2 seconds wait.
n * 2 ].
aPromise := [ 1 / 4 ] asAsyncPromise.
aPromise wait.
aPromise
asyncThen: [ :n |
2 seconds wait.
n * 2 ].
Nested Promises
If a promise returns another promise then they are recursively unfolded:
[ 42 ] asAsyncPromise
then: [ :n | [ n * 2 ] asAsyncPromise ]
[ [ 42 ] asAsyncPromise ] asAsyncPromise
then: [ :n | [ n * 2 ] asAsyncPromise ]