0
# Node.js Integration
1
2
Comprehensive Node.js callback integration for converting existing callback-based APIs to promises and integrating with the Node.js ecosystem.
3
4
## Capabilities
5
6
### Callback Function Conversion
7
8
Converts Node.js callback-style functions to promise-returning functions.
9
10
```javascript { .api }
11
/**
12
* Wraps Node-style callback function to return promises
13
* @param callback - Node.js callback function (error, result) => void
14
* @param pattern - Optional parameter processing pattern
15
* @returns Promise-returning version of the function
16
*/
17
function Q.denodeify(callback, pattern);
18
```
19
20
**Usage Examples:**
21
22
```javascript
23
const Q = require("q");
24
const fs = require("fs");
25
26
// Convert filesystem functions
27
const readFile = Q.denodeify(fs.readFile);
28
const writeFile = Q.denodeify(fs.writeFile);
29
const stat = Q.denodeify(fs.stat);
30
31
// Use converted functions
32
readFile("package.json", "utf8")
33
.then(data => JSON.parse(data))
34
.then(json => console.log("Package name:", json.name))
35
.catch(error => console.error("Read error:", error));
36
37
// Convert custom callback functions
38
function oldStyleFunction(param1, param2, callback) {
39
setTimeout(() => {
40
if (param1 && param2) {
41
callback(null, param1 + param2);
42
} else {
43
callback(new Error("Invalid parameters"));
44
}
45
}, 100);
46
}
47
48
const newStyleFunction = Q.denodeify(oldStyleFunction);
49
50
newStyleFunction("Hello", " World")
51
.then(result => console.log(result)) // "Hello World"
52
.catch(error => console.error(error));
53
54
// Convert with pattern (for special cases)
55
const execFile = Q.denodeify(require("child_process").execFile);
56
execFile("ls", ["-la"])
57
.then(stdout => console.log(stdout))
58
.catch(error => console.error("Command failed:", error));
59
```
60
61
### Method Invocation
62
63
Calls Node.js style methods on objects and returns promises.
64
65
```javascript { .api }
66
/**
67
* Calls Node-style method and returns promise
68
* @param object - Object containing the method
69
* @param name - Method name to call
70
* @param ...args - Arguments to pass to method
71
* @returns Promise for method result
72
*/
73
function Q.ninvoke(object, name, ...args);
74
75
/**
76
* Calls Node-style method on fulfilled object
77
* @param name - Method name to call
78
* @param ...args - Arguments to pass to method
79
* @returns Promise for method result
80
*/
81
promise.ninvoke(name, ...args);
82
```
83
84
**Usage Examples:**
85
86
```javascript
87
const Q = require("q");
88
const fs = require("fs");
89
90
// Static method invocation
91
Q.ninvoke(fs, "readFile", "config.json", "utf8")
92
.then(data => JSON.parse(data))
93
.then(config => console.log("Config loaded:", config))
94
.catch(error => console.error("Config load failed:", error));
95
96
// Instance method invocation with promise of object
97
const redisClient = getRedisClient();
98
99
Q.resolve(redisClient)
100
.ninvoke("get", "user:123")
101
.then(userData => {
102
if (userData) {
103
return JSON.parse(userData);
104
}
105
throw new Error("User not found");
106
})
107
.then(user => console.log("User:", user))
108
.catch(error => console.error("Redis error:", error));
109
110
// Chaining method calls
111
const dbConnection = connectToDatabase();
112
113
Q.resolve(dbConnection)
114
.ninvoke("query", "SELECT * FROM users WHERE active = ?", [true])
115
.then(users => {
116
console.log(`Found ${users.length} active users`);
117
return Q.ninvoke(dbConnection, "query",
118
"UPDATE users SET last_seen = NOW() WHERE active = ?", [true]);
119
})
120
.then(result => console.log("Updated timestamps"))
121
.catch(error => console.error("Database error:", error));
122
```
123
124
### Promise to Callback Conversion
125
126
Converts promises back to Node.js callback style for integration with callback-expecting code.
127
128
```javascript { .api }
129
/**
130
* Converts promise to Node-style callback pattern
131
* @param nodeback - Node.js style callback function (error, result) => void
132
* @returns void (calls nodeback with result)
133
*/
134
promise.nodeify(nodeback);
135
```
136
137
**Usage Examples:**
138
139
```javascript
140
const Q = require("q");
141
142
// Convert promise to callback for legacy API
143
function legacyFunction(callback) {
144
const promise = fetchUserData()
145
.then(user => processUser(user))
146
.then(result => ({ success: true, data: result }))
147
.catch(error => ({ success: false, error: error.message }));
148
149
promise.nodeify(callback);
150
}
151
152
// Use with traditional callback patterns
153
legacyFunction((error, result) => {
154
if (error) {
155
console.error("Operation failed:", error);
156
} else {
157
console.log("Operation result:", result);
158
}
159
});
160
161
// Integration with Express.js middleware
162
function promiseMiddleware(req, res, next) {
163
authenticateUser(req.headers.authorization)
164
.then(user => {
165
req.user = user;
166
return user;
167
})
168
.nodeify(next); // Calls next() on success, next(error) on failure
169
}
170
171
// Callback-style wrapper for promise-based function
172
function fetchDataCallback(userId, callback) {
173
Q.resolve(userId)
174
.then(id => validateUserId(id))
175
.then(id => fetchFromDatabase(id))
176
.then(data => processData(data))
177
.nodeify(callback);
178
}
179
180
// Using the callback wrapper
181
fetchDataCallback("user123", (error, data) => {
182
if (error) {
183
console.error("Fetch failed:", error);
184
} else {
185
console.log("Data received:", data);
186
}
187
});
188
```
189
190
### Deferred Node.js Integration
191
192
Creating Node.js compatible resolvers from deferred objects.
193
194
```javascript { .api }
195
/**
196
* Creates Node-style callback resolver from deferred
197
* @param unpack - Optional flag to unpack single-element arrays
198
* @returns Node.js callback function
199
*/
200
deferred.makeNodeResolver(unpack);
201
```
202
203
**Usage Examples:**
204
205
```javascript
206
const Q = require("q");
207
const fs = require("fs");
208
209
// Use deferred with Node.js APIs
210
function readFilePromise(filename) {
211
const deferred = Q.defer();
212
const nodeCallback = deferred.makeNodeResolver();
213
214
fs.readFile(filename, "utf8", nodeCallback);
215
216
return deferred.promise;
217
}
218
219
// With unpacking for single results
220
function statFilePromise(filename) {
221
const deferred = Q.defer();
222
const nodeCallback = deferred.makeNodeResolver(true);
223
224
fs.stat(filename, nodeCallback);
225
226
return deferred.promise;
227
}
228
229
// Complex integration example
230
function executeQuery(sql, params) {
231
const deferred = Q.defer();
232
const nodeCallback = deferred.makeNodeResolver();
233
234
database.query(sql, params, (error, results, fields) => {
235
if (error) {
236
nodeCallback(error);
237
} else {
238
nodeCallback(null, { results, fields });
239
}
240
});
241
242
return deferred.promise;
243
}
244
245
// Using the promise-wrapped function
246
executeQuery("SELECT * FROM users WHERE id = ?", [123])
247
.then(({ results, fields }) => {
248
console.log("Query results:", results);
249
console.log("Field info:", fields);
250
})
251
.catch(error => console.error("Query failed:", error));
252
```
253
254
## Common Integration Patterns
255
256
### File System Operations
257
258
```javascript
259
const Q = require("q");
260
const fs = require("fs");
261
const path = require("path");
262
263
// Create promise-based fs operations
264
const readFile = Q.denodeify(fs.readFile);
265
const writeFile = Q.denodeify(fs.writeFile);
266
const readdir = Q.denodeify(fs.readdir);
267
const stat = Q.denodeify(fs.stat);
268
269
// Complex file operations
270
function processDirectory(dirPath) {
271
return readdir(dirPath)
272
.then(files => {
273
const filePromises = files.map(file => {
274
const fullPath = path.join(dirPath, file);
275
return stat(fullPath)
276
.then(stats => ({ name: file, path: fullPath, stats }));
277
});
278
return Q.all(filePromises);
279
})
280
.then(fileInfos => {
281
const textFiles = fileInfos.filter(info =>
282
info.stats.isFile() && path.extname(info.name) === ".txt"
283
);
284
return textFiles;
285
});
286
}
287
```
288
289
### Database Integration
290
291
```javascript
292
const Q = require("q");
293
294
// Wrap database connection methods
295
function createDbWrapper(connection) {
296
return {
297
query: Q.denodeify(connection.query.bind(connection)),
298
beginTransaction: Q.denodeify(connection.beginTransaction.bind(connection)),
299
commit: Q.denodeify(connection.commit.bind(connection)),
300
rollback: Q.denodeify(connection.rollback.bind(connection))
301
};
302
}
303
304
// Use wrapped database
305
const db = createDbWrapper(mysqlConnection);
306
307
function updateUserWithTransaction(userId, userData) {
308
return db.beginTransaction()
309
.then(() => db.query("UPDATE users SET ? WHERE id = ?", [userData, userId]))
310
.then(result => {
311
if (result.affectedRows === 0) {
312
throw new Error("User not found");
313
}
314
return db.commit();
315
})
316
.catch(error => {
317
return db.rollback().then(() => {
318
throw error;
319
});
320
});
321
}
322
```