Promise then:, asyncThen:, and then:otherwise: usage

Basic

TAsyncPromise Trait named: #TAsyncPromise instanceVariableNames: '' package: 'Futures-Base - Promises' returns computed value:

[ 1 / 4 ] asAsyncPromise
  

And may hold a rejected value (error):

[ 1 / 0 ] asAsyncPromise
  

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 ]