Class: Ione::Future
- Inherits:
-
Object
- Object
- Ione::Future
- Extended by:
- Factories
- Includes:
- Callbacks, Combinators
- Defined in:
- lib/ione/future.rb
Overview
A future represents the value of a process that may not yet have completed.
A future is either pending or completed and there are two ways to complete a future: either by resolving it to a value, or by failing it.
A future is usually created by first creating a Promise and returning that promise's future to the caller. The promise can then be fulfilled which resolves the future – see below for an example of thi.
The key thing about futures is that they compose. If you have a future you can transform it and combine without waiting for its value to be available. This means that you can model a series of asynchronous operations without worrying about which order they will complete in, or what happens if any of them fail. You can describe the steps you want to happen if all goes well, and add a handler at the end to capture errors, like you can with synchronous code and exception handlers. You can also add steps that recover from failures. See below, and the docs for Combinators for examples on how to compose asynchronous operations.
The mixins Combinators, Callbacks and Factories contain most of the method you would use to work with futures, and can be used for creating bridges to other futures implementations.
Defined Under Namespace
Modules: Callbacks, Combinators, Factories
Constant Summary collapse
- PENDING_STATE =
0
- RESOLVED_STATE =
1
- FAILED_STATE =
2
Instance Method Summary collapse
-
#completed? ⇒ Boolean
Returns true if this future is resolved or failed.
-
#failed? ⇒ Boolean
Returns true if this future has failed.
-
#on_complete {|value, error, future| ... } ⇒ Object
Registers a listener that will be called when this future completes, i.e.
-
#resolved? ⇒ Boolean
Returns true if this future is resolved.
-
#value ⇒ Object
(also: #get)
Returns the value of this future, blocking until it is available if necessary.
Methods included from Factories
after, all, failed, first, reduce, resolved, traverse
Methods included from Callbacks
Methods included from Combinators
#fallback, #flat_map, #map, #recover, #then
Instance Method Details
#completed? ⇒ Boolean
Returns true if this future is resolved or failed
712 713 714 715 716 717 718 719 720 |
# File 'lib/ione/future.rb', line 712 def completed? return true unless @state == PENDING_STATE @lock.lock begin @state != PENDING_STATE ensure @lock.unlock end end |
#failed? ⇒ Boolean
Returns true if this future has failed
734 735 736 737 738 739 740 741 742 |
# File 'lib/ione/future.rb', line 734 def failed? return @state == FAILED_STATE unless @state == PENDING_STATE @lock.lock begin @state == FAILED_STATE ensure @lock.unlock end end |
#on_complete {|value, error, future| ... } ⇒ Object
Depending on the arity of the listener it will be passed different arguments. When the listener takes one argument it will receive the future itself as argument (this is backwards compatible with the pre v1.2 behaviour), with two arguments the value and error are given, with three arguments the value, error and the future itself will be given. The listener can also take no arguments. See the tests to find out the nitty-gritty details, for example the behaviour with different combinations of variable arguments and default values.
Most of the time you will use Ione::Future::Callbacks#on_value and Ione::Future::Callbacks#on_failure, and not instead of this method.
Registers a listener that will be called when this future completes, i.e. resolves or fails. The listener will be called with the future as solve argument.
The order in which listeners are called is not defined and implementation dependent. The thread the listener will be called on is also not defined and implementation dependent. The default implementation calls listeners registered before completion on the thread that completed the future, and listeners registered after completions on the thread that registers the listener – but this may change in the future, and may be different in special circumstances.
When a listener raises an error it will be swallowed and not re-raised. The reason for this is that the processing of the callback may be done in a context that does not expect, nor can recover from, errors. Not swallowing errors would stop other listeners from being called. If it appears as if a listener is not called, first make sure it is not raising any errors (even a syntax error or a spelling mistake in a method or variable name will not be hidden).
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 |
# File 'lib/ione/future.rb', line 644 def on_complete(&listener) run_immediately = false if @state != PENDING_STATE run_immediately = true else @lock.lock begin if @state == PENDING_STATE @listeners << listener else run_immediately = true end ensure @lock.unlock end end if run_immediately call_listener(listener) end nil end |
#resolved? ⇒ Boolean
Returns true if this future is resolved
723 724 725 726 727 728 729 730 731 |
# File 'lib/ione/future.rb', line 723 def resolved? return @state == RESOLVED_STATE unless @state == PENDING_STATE @lock.lock begin @state == RESOLVED_STATE ensure @lock.unlock end end |
#value ⇒ Object Also known as: get
This is a blocking operation and should be used with caution. You should never call this method in a block given to any of the other methods on Ione::Future. Prefer using combinator methods like Ione::Future::Combinators#map and Ione::Future::Combinators#flat_map to compose operations asynchronously, or use Ione::Future::Callbacks#on_value, Ione::Future::Callbacks#on_failure or #on_complete to listen for values and/or failures.
Returns the value of this future, blocking until it is available if necessary.
If the future fails this method will raise the error that failed the future.
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 |
# File 'lib/ione/future.rb', line 684 def value raise @error if @state == FAILED_STATE return @value if @state == RESOLVED_STATE semaphore = nil @lock.lock begin raise @error if @state == FAILED_STATE return @value if @state == RESOLVED_STATE semaphore = Queue.new u = proc { semaphore << :unblock } @listeners << u ensure @lock.unlock end while true @lock.lock begin raise @error if @state == FAILED_STATE return @value if @state == RESOLVED_STATE ensure @lock.unlock end semaphore.pop end end |