@@ -8,15 +8,8 @@ A trivial implementation of timeouts for `Promise`s, built on top of [ReactPHP](
8
8
9
9
* [ Usage] ( #usage )
10
10
* [ 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 )
16
11
* [ resolve()] ( #resolve )
17
- * [ Resolve cancellation] ( #resolve-cancellation )
18
12
* [ reject()] ( #reject )
19
- * [ Reject cancellation] ( #reject-cancellation )
20
13
* [ TimeoutException] ( #timeoutexception )
21
14
* [ getTimeout()] ( #gettimeout )
22
15
* [ Install] ( #install )
@@ -53,18 +46,25 @@ Timer\timeout(…);
53
46
### timeout()
54
47
55
48
The ` 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* .
59
50
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 ) .
63
63
64
64
Internally, 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.
68
68
69
69
If the input ` $promise ` is already settled, then the resulting promise will
70
70
resolve or reject immediately without starting a timer at all.
@@ -118,151 +118,38 @@ React\Promise\Timer\timeout($promise, 10.0)
118
118
;
119
119
```
120
120
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.
138
127
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.
142
130
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
144
135
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.
187
140
188
141
``` php
189
142
$promise = accessSomeRemoteResource();
190
143
$timeout = React\Promise\Timer\timeout($promise, 10.0);
191
144
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
-
251
145
$timeout->cancel();
252
146
```
253
147
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 ) .
264
150
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:
266
153
267
154
``` php
268
155
$promises = array(
@@ -271,22 +158,23 @@ $promises = array(
271
158
accessSomeRemoteResource()
272
159
);
273
160
274
- $promise = \ React\Promise\all($promises);
161
+ $promise = React\Promise\all($promises);
275
162
276
163
React\Promise\Timer\timeout($promise, 10)->then(function ($values) {
277
164
// *all* promises resolved
278
165
});
279
166
```
280
167
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.
282
170
283
171
For more details on the promise primitives, please refer to the
284
172
[ Promise documentation] ( https://github.com/reactphp/promise#functions ) .
285
173
286
174
### resolve()
287
175
288
176
The ` 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.
290
178
291
179
``` php
292
180
React\Promise\Timer\resolve(1.5)->then(function ($time) {
@@ -295,32 +183,30 @@ React\Promise\Timer\resolve(1.5)->then(function ($time) {
295
183
```
296
184
297
185
Internally, 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.
301
189
302
190
This function takes an optional ` LoopInterface|null $loop ` parameter that can be used to
303
191
pass the event loop instance to use. You can use a ` null ` value here in order to
304
192
use the [ default loop] ( https://github.com/reactphp/event-loop#loop ) . This value
305
193
SHOULD NOT be given unless you're sure you want to explicitly use a given event
306
194
loop instance.
307
195
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.
311
199
312
200
``` php
313
201
$timer = React\Promise\Timer\resolve(2.0);
314
202
315
203
$timer->cancel();
316
204
```
317
205
318
- This will abort the timer and * reject* with a ` RuntimeException ` .
319
-
320
206
### reject()
321
207
322
- The ` reject(float $time, ?LoopInterface $loop = null): PromiseInterface<TimeoutException, RuntimeException> ` function can be used
323
- to create a new Promise which rejects in ` $time ` seconds with a ` TimeoutException ` .
208
+ The ` reject(float $time, ?LoopInterface $loop = null): PromiseInterface<TimeoutException, RuntimeException> ` function can be used to
209
+ create a new promise which rejects in ` $time ` seconds with a ` TimeoutException ` .
324
210
325
211
``` php
326
212
React\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
329
215
```
330
216
331
217
Internally, 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.
335
221
336
222
This function takes an optional ` LoopInterface|null $loop ` parameter that can be used to
337
223
pass the event loop instance to use. You can use a ` null ` value here in order to
338
224
use the [ default loop] ( https://github.com/reactphp/event-loop#loop ) . This value
339
225
SHOULD NOT be given unless you're sure you want to explicitly use a given event
340
226
loop instance.
341
227
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.
348
231
349
232
``` php
350
233
$timer = React\Promise\Timer\reject(2.0);
351
234
352
235
$timer->cancel();
353
236
```
354
237
355
- This will abort the timer and * reject* with a ` RuntimeException ` .
356
-
357
238
### TimeoutException
358
239
359
240
The ` TimeoutException ` extends PHP's built-in ` RuntimeException ` .
0 commit comments