@@ -48,6 +48,57 @@ 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 handling with ` options.timeout `
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+ console .log (' Response:' , response .sum );
91+ } catch (error) {
92+ if (error .name === ' TimeoutError' ) {
93+ console .log (' Request timed out' );
94+ } else if (error .name === ' AbortError' ) {
95+ console .log (' Request was cancelled' );
96+ } else {
97+ console .error (' Service error:' , error .message );
98+ }
99+ }
100+ ```
101+
51102### GetMap Service
52103
53104#### Service Server (` service/getmap-service-example.js ` )
@@ -129,6 +180,41 @@ ROS 2 services provide a request-response communication pattern where clients se
129180 Result: object { sum: 79n }
130181 ```
131182
183+ ### Running the Async AddTwoInts Client Example
184+
185+ 1 . ** Prerequisites** : Ensure ROS 2 is installed and sourced
186+
187+ 2 . ** Start the Service Server** : Use the same service server as above:
188+
189+ ``` bash
190+ cd /path/to/rclnodejs
191+ node example/services/service/service-example.js
192+ ```
193+
194+ 3 . ** Start the Async Client** : In another terminal, run:
195+
196+ ``` bash
197+ cd /path/to/rclnodejs
198+ node example/services/client/async-client-example.js
199+ ```
200+
201+ 4 . ** Expected Output** :
202+
203+ ** Service Server Terminal** : (Same as regular client)
204+
205+ ```
206+ Incoming request: object { a: 42n, b: 37n }
207+ Sending response: object { sum: 79n }
208+ --
209+ ```
210+
211+ ** Async Client Terminal** :
212+
213+ ```
214+ Sending: object { a: 42n, b: 37n }
215+ Result: object { sum: 79n }
216+ ```
217+
132218### Running the GetMap Service Example
133219
1342201 . ** Prerequisites** : Ensure ROS 2 is installed and sourced
@@ -236,8 +322,11 @@ This script automatically starts the service, tests the client, and cleans up.
236322
237323### Programming Patterns
238324
239- - ** Async/Await** : Modern JavaScript patterns for asynchronous operations
240- - ** Callback Handling** : Response processing using callback functions
325+ - ** Modern Async/Await** : Clean Promise-based service calls with ` sendRequestAsync() `
326+ - ** Traditional Callbacks** : Response processing using callback functions with ` sendRequest() `
327+ - ** Error Handling** : Proper error handling with try/catch blocks and specific error types (async only)
328+ - ** Timeout Management** : Built-in timeout support to prevent hanging requests (async only)
329+ - ** Request Cancellation** : AbortController support for user-cancellable operations (async only)
241330- ** Resource Management** : Proper node shutdown and cleanup
242331- ** Data Analysis** : Processing and interpreting received data
243332- ** Visualization** : Converting data to human-readable formats
@@ -331,18 +420,23 @@ int8[] data
331420### Common Issues
332421
3334221 . ** Service Not Available** :
334-
335423 - Ensure the service server is running before starting the client
336424 - Check that both use the same service name (` add_two_ints ` )
337425
3384262 . ** Type Errors** :
339-
340427 - Ensure you're using ` BigInt() ` for integer values, not regular numbers
341428 - Use ` response.template ` to get the correct response structure
342429
3434303 . ** Client Hangs** :
344431 - The client waits for service availability with a 1-second timeout
345432 - If the service isn't available, the client will log an error and shut down
433+ - For async clients, use timeout options: ` client.sendRequestAsync(request, { timeout: 5000 }) `
434+
435+ 4 . ** Async/Await Issues** (applies only to ` sendRequestAsync() ` ):
436+ - ** Unhandled Promise Rejections** : Always use try/catch blocks around ` sendRequestAsync() `
437+ - ** Timeout Errors** : Handle ` TimeoutError ` specifically for timeout scenarios (async only)
438+ - ** Cancelled Requests** : Handle ` AbortError ` when using AbortController cancellation (async only)
439+ - ** Mixed Patterns** : You can use both ` sendRequest() ` and ` sendRequestAsync() ` in the same code
346440
347441### Debugging Tips
348442
@@ -354,6 +448,10 @@ int8[] data
354448
355449- Both examples use the standard rclnodejs initialization pattern
356450- The service server runs continuously until manually terminated
357- - The client performs a single request-response cycle then exits
451+ - The traditional client performs a single request-response cycle then exits
452+ - The async client demonstrates multiple patterns and then exits
453+ - ** New async/await support** : Use ` sendRequestAsync() ` for modern Promise-based patterns
454+ - ** Full backward compatibility** : Existing ` sendRequest() ` callback-based code continues to work unchanged
455+ - ** TypeScript support** : Full type safety available for async methods
358456- Service introspection is only available in ROS 2 Iron and later distributions
359457- BigInt is required for integer message fields to maintain precision
0 commit comments