@@ -8,15 +8,8 @@ A trivial implementation of timeouts for `Promise`s, built on top of [ReactPHP](
88
99* [ Usage] ( #usage )
1010 * [ timeout()] ( #timeout )
11- * [ Timeout cancellation] ( #timeout-cancellation )
12- * [ Cancellation handler] ( #cancellation-handler )
13- * [ Input cancellation] ( #input-cancellation )
14- * [ Output cancellation] ( #output-cancellation )
15- * [ Collections] ( #collections )
1611 * [ resolve()] ( #resolve )
17- * [ Resolve cancellation] ( #resolve-cancellation )
1812 * [ reject()] ( #reject )
19- * [ Reject cancellation] ( #reject-cancellation )
2013 * [ TimeoutException] ( #timeoutexception )
2114 * [ getTimeout()] ( #gettimeout )
2215* [ Install] ( #install )
@@ -53,18 +46,25 @@ Timer\timeout(…);
5346### timeout()
5447
5548The ` timeout(PromiseInterface<mixed, Exception|mixed> $promise, float $time, ?LoopInterface $loop = null): PromiseInterface<mixed, TimeoutException|Exception|mixed> ` function can be used to
56- * cancel* operations that take * too long* .
57- You need to pass in an input ` $promise ` that represents a pending operation and timeout parameters.
58- It returns a new ` Promise ` with the following resolution behavior:
49+ cancel operations that take * too long* .
5950
60- * If the input ` $promise ` resolves before ` $time ` seconds, resolve the resulting promise with its fulfillment value.
61- * If the input ` $promise ` rejects before ` $time ` seconds, reject the resulting promise with its rejection value.
62- * If the input ` $promise ` does not settle before ` $time ` seconds, * cancel* the operation and reject the resulting promise with a [ ` TimeoutException ` ] ( #timeoutexception ) .
51+ You need to pass in an input ` $promise ` that represents a pending operation
52+ and timeout parameters. It returns a new promise with the following
53+ resolution behavior:
54+
55+ - If the input ` $promise ` resolves before ` $time ` seconds, resolve the
56+ resulting promise with its fulfillment value.
57+
58+ - If the input ` $promise ` rejects before ` $time ` seconds, reject the
59+ resulting promise with its rejection value.
60+
61+ - If the input ` $promise ` does not settle before ` $time ` seconds, * cancel*
62+ the operation and reject the resulting promise with a [ ` TimeoutException ` ] ( #timeoutexception ) .
6363
6464Internally, the given ` $time ` value will be used to start a timer that will
65- * cancel* the pending operation once it triggers.
66- This implies that if you pass a really small (or negative) value, it will still
67- start a timer and will thus trigger at the earliest possible time in the future.
65+ * cancel* the pending operation once it triggers. This implies that if you
66+ pass a really small (or negative) value, it will still start a timer and will
67+ thus trigger at the earliest possible time in the future.
6868
6969If the input ` $promise ` is already settled, then the resulting promise will
7070resolve or reject immediately without starting a timer at all.
@@ -118,151 +118,38 @@ React\Promise\Timer\timeout($promise, 10.0)
118118;
119119```
120120
121- #### Timeout cancellation
122-
123- As discussed above, the [ ` timeout() ` ] ( #timeout ) function will * cancel* the
124- underlying operation if it takes * too long* .
125- This means that you can be sure the resulting promise will then be rejected
126- with a [ ` TimeoutException ` ] ( #timeoutexception ) .
127-
128- However, what happens to the underlying input ` $promise ` is a bit more tricky:
129- Once the timer fires, we will try to call
130- [ ` $promise->cancel() ` ] ( https://github.com/reactphp/promise#cancellablepromiseinterfacecancel )
131- on the input ` $promise ` which in turn invokes its [ cancellation handler] ( #cancellation-handler ) .
132-
133- This means that it's actually up the input ` $promise ` to handle
134- [ cancellation support] ( https://github.com/reactphp/promise#cancellablepromiseinterface ) .
135-
136- * A common use case involves cleaning up any resources like open network sockets or
137- file handles or terminating external processes or timers.
121+ As discussed above, the [ ` timeout() ` ] ( #timeout ) function will take care of
122+ the underlying operation if it takes * too long* . In this case, you can be
123+ sure the resulting promise will always be rejected with a
124+ [ ` TimeoutException ` ] ( #timeoutexception ) . On top of this, the function will
125+ try to * cancel* the underlying operation. Responsibility for this
126+ cancellation logic is left up to the underlying operation.
138127
139- * If the given input ` $promise ` does not support cancellation, then this is a NO-OP.
140- This means that while the resulting promise will still be rejected, the underlying
141- input ` $promise ` may still be pending and can hence continue consuming resources.
128+ - A common use case involves cleaning up any resources like open network
129+ sockets or file handles or terminating external processes or timers.
142130
143- See the following chapter for more details on the cancellation handler.
131+ - If the given input ` $promise ` does not support cancellation, then this is a
132+ NO-OP. This means that while the resulting promise will still be rejected,
133+ the underlying input ` $promise ` may still be pending and can hence continue
134+ consuming resources
144135
145- #### Cancellation handler
146-
147- For example, an implementation for the above operation could look like this:
148-
149- ``` php
150- function accessSomeRemoteResource()
151- {
152- return new Promise(
153- function ($resolve, $reject) use (& $socket) {
154- // this will be called once the promise is created
155- // a common use case involves opening any resources and eventually resolving
156- $socket = createSocket();
157- $socket->on('data', function ($data) use ($resolve) {
158- $resolve($data);
159- });
160- },
161- function ($resolve, $reject) use (& $socket) {
162- // this will be called once calling `cancel()` on this promise
163- // a common use case involves cleaning any resources and then rejecting
164- $socket->close();
165- $reject(new \RuntimeException('Operation cancelled'));
166- }
167- );
168- }
169- ```
170-
171- In this example, calling ` $promise->cancel() ` will invoke the registered cancellation
172- handler which then closes the network socket and rejects the ` Promise ` instance.
173-
174- If no cancellation handler is passed to the ` Promise ` constructor, then invoking
175- its ` cancel() ` method it is effectively a NO-OP.
176- This means that it may still be pending and can hence continue consuming resources.
177-
178- For more details on the promise cancellation, please refer to the
179- [ Promise documentation] ( https://github.com/reactphp/promise#cancellablepromiseinterface ) .
180-
181- #### Input cancellation
182-
183- Irrespective of the timeout handling, you can also explicitly ` cancel() ` the
184- input ` $promise ` at any time.
185- This means that the ` timeout() ` handling does not affect cancellation of the
186- input ` $promise ` , as demonstrated in the following example:
136+ On top of this, the returned promise is implemented in such a way that it can
137+ be cancelled when it is still pending. Cancelling a pending promise will
138+ cancel the underlying operation. As discussed, above, responsibility for this
139+ cancellation logic is left up to the underlying operation.
187140
188141``` php
189142$promise = accessSomeRemoteResource();
190143$timeout = React\Promise\Timer\timeout($promise, 10.0);
191144
192- $promise->cancel();
193- ```
194-
195- The registered [ cancellation handler] ( #cancellation-handler ) is responsible for
196- handling the ` cancel() ` call:
197-
198- * A described above, a common use involves resource cleanup and will then * reject*
199- the ` Promise ` .
200- If the input ` $promise ` is being rejected, then the timeout will be aborted
201- and the resulting promise will also be rejected.
202- * If the input ` $promise ` is still pending, then the timout will continue
203- running until the timer expires.
204- The same happens if the input ` $promise ` does not register a
205- [ cancellation handler] ( #cancellation-handler ) .
206-
207- #### Output cancellation
208-
209- Similarily, you can also explicitly ` cancel() ` the resulting promise like this:
210-
211- ``` php
212- $promise = accessSomeRemoteResource();
213- $timeout = React\Promise\Timer\timeout($promise, 10.0);
214-
215- $timeout->cancel();
216- ```
217-
218- Note how this looks very similar to the above [ input cancellation] ( #input-cancellation )
219- example. Accordingly, it also behaves very similar.
220-
221- Calling ` cancel() ` on the resulting promise will merely try
222- to ` cancel() ` the input ` $promise ` .
223- This means that we do not take over responsibility of the outcome and it's
224- entirely up to the input ` $promise ` to handle cancellation support.
225-
226- The registered [ cancellation handler] ( #cancellation-handler ) is responsible for
227- handling the ` cancel() ` call:
228-
229- * As described above, a common use involves resource cleanup and will then * reject*
230- the ` Promise ` .
231- If the input ` $promise ` is being rejected, then the timeout will be aborted
232- and the resulting promise will also be rejected.
233- * If the input ` $promise ` is still pending, then the timout will continue
234- running until the timer expires.
235- The same happens if the input ` $promise ` does not register a
236- [ cancellation handler] ( #cancellation-handler ) .
237-
238- To re-iterate, note that calling ` cancel() ` on the resulting promise will merely
239- try to cancel the input ` $promise ` only.
240- It is then up to the cancellation handler of the input promise to settle the promise.
241- If the input promise is still pending when the timeout occurs, then the normal
242- [ timeout cancellation] ( #timeout-cancellation ) handling will trigger, effectively rejecting
243- the output promise with a [ ` TimeoutException ` ] ( #timeoutexception ) .
244-
245- This is done for consistency with the [ timeout cancellation] ( #timeout-cancellation )
246- handling and also because it is assumed this is often used like this:
247-
248- ``` php
249- $timeout = React\Promise\Timer\timeout(accessSomeRemoteResource(), 10.0);
250-
251145$timeout->cancel();
252146```
253147
254- As described above, this example works as expected and cleans up any resources
255- allocated for the input ` $promise ` .
256-
257- Note that if the given input ` $promise ` does not support cancellation, then this
258- is a NO-OP.
259- This means that while the resulting promise will still be rejected after the
260- timeout, the underlying input ` $promise ` may still be pending and can hence
261- continue consuming resources.
262-
263- #### Collections
148+ For more details on the promise cancellation, please refer to the
149+ [ Promise documentation] ( https://github.com/reactphp/promise#cancellablepromiseinterface ) .
264150
265- If you want to wait for multiple promises to resolve, you can use the normal promise primitives like this:
151+ If you want to wait for multiple promises to resolve, you can use the normal
152+ promise primitives like this:
266153
267154``` php
268155$promises = array(
@@ -271,22 +158,23 @@ $promises = array(
271158 accessSomeRemoteResource()
272159);
273160
274- $promise = \ React\Promise\all($promises);
161+ $promise = React\Promise\all($promises);
275162
276163React\Promise\Timer\timeout($promise, 10)->then(function ($values) {
277164 // *all* promises resolved
278165});
279166```
280167
281- The applies to all promise collection primitives alike, i.e. ` all() ` , ` race() ` , ` any() ` , ` some() ` etc.
168+ The applies to all promise collection primitives alike, i.e. ` all() ` ,
169+ ` race() ` , ` any() ` , ` some() ` etc.
282170
283171For more details on the promise primitives, please refer to the
284172[ Promise documentation] ( https://github.com/reactphp/promise#functions ) .
285173
286174### resolve()
287175
288176The ` resolve(float $time, ?LoopInterface $loop = null): PromiseInterface<float, RuntimeException> ` function can be used to
289- create a new Promise that resolves in ` $time ` seconds with the ` $time ` as the fulfillment value.
177+ create a new promise that resolves in ` $time ` seconds with the ` $time ` as the fulfillment value.
290178
291179``` php
292180React\Promise\Timer\resolve(1.5)->then(function ($time) {
@@ -295,32 +183,30 @@ React\Promise\Timer\resolve(1.5)->then(function ($time) {
295183```
296184
297185Internally, the given ` $time ` value will be used to start a timer that will
298- resolve the promise once it triggers.
299- This implies that if you pass a really small (or negative) value, it will still
300- start a timer and will thus trigger at the earliest possible time in the future.
186+ resolve the promise once it triggers. This implies that if you pass a really
187+ small (or negative) value, it will still start a timer and will thus trigger
188+ at the earliest possible time in the future.
301189
302190This function takes an optional ` LoopInterface|null $loop ` parameter that can be used to
303191pass the event loop instance to use. You can use a ` null ` value here in order to
304192use the [ default loop] ( https://github.com/reactphp/event-loop#loop ) . This value
305193SHOULD NOT be given unless you're sure you want to explicitly use a given event
306194loop instance.
307195
308- #### Resolve cancellation
309-
310- You can explicitly ` cancel() ` the resulting timer promise at any time:
196+ The returned promise is implemented in such a way that it can be cancelled
197+ when it is still pending. Cancelling a pending promise will reject its value
198+ with a ` RuntimeException ` and clean up any pending timers.
311199
312200``` php
313201$timer = React\Promise\Timer\resolve(2.0);
314202
315203$timer->cancel();
316204```
317205
318- This will abort the timer and * reject* with a ` RuntimeException ` .
319-
320206### reject()
321207
322208The ` reject(float $time, ?LoopInterface $loop = null): PromiseInterface<void, TimeoutException|RuntimeException> ` function can be used to
323- create a new Promise which rejects in ` $time ` seconds with a ` TimeoutException ` .
209+ create a new promise which rejects in ` $time ` seconds with a ` TimeoutException ` .
324210
325211``` php
326212React\Promise\Timer\reject(2.0)->then(null, function (React\Promise\Timer\TimeoutException $e) {
@@ -329,31 +215,26 @@ React\Promise\Timer\reject(2.0)->then(null, function (React\Promise\Timer\Timeou
329215```
330216
331217Internally, the given ` $time ` value will be used to start a timer that will
332- reject the promise once it triggers.
333- This implies that if you pass a really small (or negative) value, it will still
334- start a timer and will thus trigger at the earliest possible time in the future.
218+ reject the promise once it triggers. This implies that if you pass a really
219+ small (or negative) value, it will still start a timer and will thus trigger
220+ at the earliest possible time in the future.
335221
336222This function takes an optional ` LoopInterface|null $loop ` parameter that can be used to
337223pass the event loop instance to use. You can use a ` null ` value here in order to
338224use the [ default loop] ( https://github.com/reactphp/event-loop#loop ) . This value
339225SHOULD NOT be given unless you're sure you want to explicitly use a given event
340226loop instance.
341227
342- This function complements the [ ` resolve() ` ] ( #resolve ) function
343- and can be used as a basic building block for higher-level promise consumers.
344-
345- #### Reject cancellation
346-
347- You can explicitly ` cancel() ` the resulting timer promise at any time:
228+ The returned promise is implemented in such a way that it can be cancelled
229+ when it is still pending. Cancelling a pending promise will reject its value
230+ with a ` RuntimeException ` and clean up any pending timers.
348231
349232``` php
350233$timer = React\Promise\Timer\reject(2.0);
351234
352235$timer->cancel();
353236```
354237
355- This will abort the timer and * reject* with a ` RuntimeException ` .
356-
357238### TimeoutException
358239
359240The ` TimeoutException ` extends PHP's built-in ` RuntimeException ` .
0 commit comments