@@ -48,6 +48,63 @@ ROS 2 services provide a request-response communication pattern where clients se
4848 - Asynchronous request handling with callbacks
4949- ** Run Command** : ` node example/services/client/client-example.js `
5050
51+ #### Async Service Client (` client/async-client-example.js ` )
52+
53+ ** Purpose** : Demonstrates modern async/await patterns for service communication, solving callback hell and providing cleaner error handling.
54+
55+ - ** Service Type** : ` example_interfaces/srv/AddTwoInts `
56+ - ** Service Name** : ` add_two_ints `
57+ - ** Functionality** :
58+ - Multiple examples showing different async patterns
59+ - Simple async/await calls without callbacks
60+ - Timeout handling with configurable timeouts
61+ - Request cancellation using AbortController
62+ - Sequential and parallel service calls
63+ - Comprehensive error handling
64+ - ** Features** :
65+ - ** Modern JavaScript** : Clean async/await syntax instead of callback hell
66+ - ** Timeout Support** : Built-in timeout with ` options.timeout ` (uses ` AbortSignal.timeout() ` internally)
67+ - ** Cancellation** : Request cancellation using ` AbortController ` and ` options.signal `
68+ - ** Error Types** : Specific error types (` TimeoutError ` , ` AbortError ` ) for better error handling (async only)
69+ - ** Backward Compatible** : Works alongside existing callback-based ` sendRequest() `
70+ - ** TypeScript Ready** : Full type safety with comprehensive TypeScript definitions
71+ - ** Run Command** : ` node example/services/client/async-client-example.js `
72+
73+ ** Key API Differences** :
74+
75+ ``` javascript
76+ client .sendRequest (request, (response ) => {
77+ console .log (' Response:' , response .sum );
78+ });
79+
80+ try {
81+ const response = await client .sendRequestAsync (request);
82+
83+ const response = await client .sendRequestAsync (request, { timeout: 5000 });
84+
85+ const controller = new AbortController ();
86+ const response = await client .sendRequestAsync (request, {
87+ signal: controller .signal ,
88+ });
89+
90+ const controller = new AbortController ();
91+ const response = await client .sendRequestAsync (request, {
92+ timeout: 5000 ,
93+ signal: controller .signal ,
94+ });
95+
96+ console .log (' Response:' , response .sum );
97+ } catch (error) {
98+ if (error .name === ' TimeoutError' ) {
99+ console .log (' Request timed out' );
100+ } else if (error .name === ' AbortError' ) {
101+ console .log (' Request was cancelled' );
102+ } else {
103+ console .error (' Service error:' , error .message );
104+ }
105+ }
106+ ```
107+
51108### GetMap Service
52109
53110#### Service Server (` service/getmap-service-example.js ` )
@@ -129,6 +186,41 @@ ROS 2 services provide a request-response communication pattern where clients se
129186 Result: object { sum: 79n }
130187 ```
131188
189+ ### Running the Async AddTwoInts Client Example
190+
191+ 1 . ** Prerequisites** : Ensure ROS 2 is installed and sourced
192+
193+ 2 . ** Start the Service Server** : Use the same service server as above:
194+
195+ ``` bash
196+ cd /path/to/rclnodejs
197+ node example/services/service/service-example.js
198+ ```
199+
200+ 3 . ** Start the Async Client** : In another terminal, run:
201+
202+ ``` bash
203+ cd /path/to/rclnodejs
204+ node example/services/client/async-client-example.js
205+ ```
206+
207+ 4 . ** Expected Output** :
208+
209+ ** Service Server Terminal** : (Same as regular client)
210+
211+ ```
212+ Incoming request: object { a: 42n, b: 37n }
213+ Sending response: object { sum: 79n }
214+ --
215+ ```
216+
217+ ** Async Client Terminal** :
218+
219+ ```
220+ Sending: object { a: 42n, b: 37n }
221+ Result: object { sum: 79n }
222+ ```
223+
132224### Running the GetMap Service Example
133225
1342261 . ** Prerequisites** : Ensure ROS 2 is installed and sourced
@@ -236,8 +328,11 @@ This script automatically starts the service, tests the client, and cleans up.
236328
237329### Programming Patterns
238330
239- - ** Async/Await** : Modern JavaScript patterns for asynchronous operations
240- - ** Callback Handling** : Response processing using callback functions
331+ - ** Modern Async/Await** : Clean Promise-based service calls with ` sendRequestAsync() `
332+ - ** Traditional Callbacks** : Response processing using callback functions with ` sendRequest() `
333+ - ** Error Handling** : Proper error handling with try/catch blocks and specific error types (async only)
334+ - ** Timeout Management** : Built-in timeout support to prevent hanging requests (async only)
335+ - ** Request Cancellation** : AbortController support for user-cancellable operations (async only)
241336- ** Resource Management** : Proper node shutdown and cleanup
242337- ** Data Analysis** : Processing and interpreting received data
243338- ** Visualization** : Converting data to human-readable formats
@@ -331,18 +426,23 @@ int8[] data
331426### Common Issues
332427
3334281 . ** Service Not Available** :
334-
335429 - Ensure the service server is running before starting the client
336430 - Check that both use the same service name (` add_two_ints ` )
337431
3384322 . ** Type Errors** :
339-
340433 - Ensure you're using ` BigInt() ` for integer values, not regular numbers
341434 - Use ` response.template ` to get the correct response structure
342435
3434363 . ** Client Hangs** :
344437 - The client waits for service availability with a 1-second timeout
345438 - If the service isn't available, the client will log an error and shut down
439+ - For async clients, use timeout options: ` client.sendRequestAsync(request, { timeout: 5000 }) `
440+
441+ 4 . ** Async/Await Issues** (applies only to ` sendRequestAsync() ` ):
442+ - ** Unhandled Promise Rejections** : Always use try/catch blocks around ` sendRequestAsync() `
443+ - ** Timeout Errors** : Handle ` TimeoutError ` specifically for timeout scenarios (async only)
444+ - ** Cancelled Requests** : Handle ` AbortError ` when using AbortController cancellation (async only)
445+ - ** Mixed Patterns** : You can use both ` sendRequest() ` and ` sendRequestAsync() ` in the same code
346446
347447### Debugging Tips
348448
@@ -354,6 +454,10 @@ int8[] data
354454
355455- Both examples use the standard rclnodejs initialization pattern
356456- The service server runs continuously until manually terminated
357- - The client performs a single request-response cycle then exits
457+ - The traditional client performs a single request-response cycle then exits
458+ - The async client demonstrates multiple patterns and then exits
459+ - ** New async/await support** : Use ` sendRequestAsync() ` for modern Promise-based patterns
460+ - ** Full backward compatibility** : Existing ` sendRequest() ` callback-based code continues to work unchanged
461+ - ** TypeScript support** : Full type safety available for async methods
358462- Service introspection is only available in ROS 2 Iron and later distributions
359463- BigInt is required for integer message fields to maintain precision
0 commit comments