0
# Functional Programming
1
2
Function wrappers and utilities for integrating promises with functional programming patterns, including async/generator support and promise-based functional composition.
3
4
## Capabilities
5
6
### Function Wrapping
7
8
Utilities for wrapping regular functions to work seamlessly with promises.
9
10
```javascript { .api }
11
/**
12
* Wraps function to return promises
13
* @param wrapped - Function to wrap for promise compatibility
14
* @returns Function that returns promises
15
*/
16
function Q.function(wrapped);
17
18
/**
19
* Decorator ensuring promise arguments and return value
20
* @param callback - Function to wrap with promise handling
21
* @returns Function that handles promise arguments and returns promises
22
*/
23
function Q.promised(callback);
24
```
25
26
**Usage Examples:**
27
28
```javascript
29
const Q = require("q");
30
31
// Wrap regular function to return promises
32
const syncAdd = (a, b) => a + b;
33
const asyncAdd = Q.function(syncAdd);
34
35
asyncAdd(5, 3)
36
.then(result => console.log("Result:", result)) // 8
37
.catch(error => console.error(error));
38
39
// Wrap function that may throw
40
const riskyFunction = (data) => {
41
if (!data) throw new Error("No data provided");
42
return data.toUpperCase();
43
};
44
45
const safeRiskyFunction = Q.function(riskyFunction);
46
47
safeRiskyFunction("hello")
48
.then(result => console.log(result)) // "HELLO"
49
.catch(error => console.error(error));
50
51
safeRiskyFunction(null)
52
.catch(error => console.error("Caught:", error.message));
53
54
// Q.promised for promise-aware functions
55
const promisedProcessor = Q.promised((data, config) => {
56
// Both data and config can be promises or values
57
return `Processed: ${data} with ${config.mode}`;
58
});
59
60
// Use with mixed promise/value arguments
61
promisedProcessor(
62
Q.delay("user data", 100),
63
{ mode: "strict" }
64
).then(result => console.log(result));
65
66
// Chain with other promise operations
67
const processUser = Q.promised((user, settings) => {
68
return {
69
id: user.id,
70
name: user.name.toUpperCase(),
71
theme: settings.theme
72
};
73
});
74
75
fetchUser(123)
76
.then(user => processUser(user, getSettings()))
77
.then(processedUser => console.log(processedUser));
78
```
79
80
### Value Comparison and Joining
81
82
Functions for comparing and joining promise values.
83
84
```javascript { .api }
85
/**
86
* Resolves to value if both promises fulfill to same value
87
* @param x - First promise or value
88
* @param y - Second promise or value
89
* @returns Promise that resolves if both values are equal
90
*/
91
function Q.join(x, y);
92
```
93
94
**Usage Examples:**
95
96
```javascript
97
const Q = require("q");
98
99
// Join with identical values
100
Q.join(Q.resolve("same"), Q.resolve("same"))
101
.then(value => console.log("Both resolved to:", value))
102
.catch(() => console.log("Values were different"));
103
104
// Join with different values (will reject)
105
Q.join(Q.resolve("first"), Q.resolve("second"))
106
.then(value => console.log("Unexpected success:", value))
107
.catch(() => console.log("Values were different, as expected"));
108
109
// Real-world example: verify consistency
110
function verifyDataConsistency(primarySource, backupSource) {
111
return Q.join(
112
fetchDataFromPrimary(primarySource),
113
fetchDataFromBackup(backupSource)
114
).then(consistentData => {
115
console.log("Data is consistent:", consistentData);
116
return consistentData;
117
}).catch(error => {
118
console.warn("Data inconsistency detected, investigating...");
119
return investigateInconsistency(primarySource, backupSource);
120
});
121
}
122
123
// Permission verification
124
function verifyUserPermissions(userId, requiredRole) {
125
return Q.join(
126
fetchUserRole(userId),
127
Q.resolve(requiredRole)
128
).then(role => {
129
console.log(`User has required role: ${role}`);
130
return true;
131
}).catch(() => {
132
console.log("User does not have required permissions");
133
return false;
134
});
135
}
136
```
137
138
### Async/Generator Support
139
140
Advanced support for ES6 generator functions and async patterns.
141
142
```javascript { .api }
143
/**
144
* Decorator for generator functions to work with promises
145
* @param makeGenerator - Generator function that yields promises
146
* @returns Function that returns promise for generator completion
147
*/
148
function Q.async(makeGenerator);
149
150
/**
151
* Runs async generator immediately with error handling
152
* @param makeGenerator - Generator function to execute
153
* @returns Promise for generator completion result
154
*/
155
function Q.spawn(makeGenerator);
156
```
157
158
**Usage Examples:**
159
160
```javascript
161
const Q = require("q");
162
163
// Q.async for reusable async generators
164
const fetchUserProfile = Q.async(function* (userId) {
165
const user = yield fetchUser(userId);
166
const preferences = yield fetchUserPreferences(userId);
167
const activity = yield fetchUserActivity(userId);
168
169
return {
170
user,
171
preferences,
172
activity,
173
lastUpdated: new Date()
174
};
175
});
176
177
// Use the async function
178
fetchUserProfile(123)
179
.then(profile => console.log("Complete profile:", profile))
180
.catch(error => console.error("Profile fetch failed:", error));
181
182
// Q.spawn for immediate execution
183
Q.spawn(function* () {
184
try {
185
console.log("Starting data migration...");
186
187
const sourceData = yield connectToSourceDatabase();
188
const targetDb = yield connectToTargetDatabase();
189
190
const users = yield sourceData.query("SELECT * FROM users");
191
console.log(`Migrating ${users.length} users...`);
192
193
for (let user of users) {
194
yield targetDb.insert("users", transformUser(user));
195
console.log(`Migrated user: ${user.name}`);
196
}
197
198
yield sourceData.close();
199
yield targetDb.close();
200
201
console.log("Migration completed successfully");
202
} catch (error) {
203
console.error("Migration failed:", error);
204
throw error;
205
}
206
}).done();
207
208
// Complex async workflow
209
const processOrderWorkflow = Q.async(function* (orderId) {
210
const order = yield fetchOrder(orderId);
211
212
// Validate order
213
const validation = yield validateOrder(order);
214
if (!validation.valid) {
215
throw new Error(`Order validation failed: ${validation.errors.join(", ")}`);
216
}
217
218
// Process payment
219
const paymentResult = yield processPayment(order.payment);
220
if (!paymentResult.success) {
221
throw new Error(`Payment failed: ${paymentResult.error}`);
222
}
223
224
// Update inventory
225
yield updateInventory(order.items);
226
227
// Schedule shipping
228
const shipping = yield scheduleShipping(order);
229
230
// Send confirmations
231
yield Q.all([
232
sendCustomerConfirmation(order.customerId, order),
233
sendMerchantNotification(order.merchantId, order),
234
logOrderProcessing(orderId, "completed")
235
]);
236
237
return {
238
orderId,
239
status: "processed",
240
paymentId: paymentResult.transactionId,
241
shippingId: shipping.trackingNumber,
242
processedAt: new Date()
243
};
244
});
245
246
// Usage
247
processOrderWorkflow("order-123")
248
.then(result => console.log("Order processed:", result))
249
.catch(error => console.error("Order processing failed:", error));
250
```
251
252
### Higher-Order Promise Functions
253
254
Advanced functional programming patterns with promises.
255
256
```javascript
257
const Q = require("q");
258
259
// Promise-based map function
260
function promiseMap(array, mapper) {
261
const mappedPromises = array.map(item => Q.resolve(item).then(mapper));
262
return Q.all(mappedPromises);
263
}
264
265
// Promise-based filter function
266
function promiseFilter(array, predicate) {
267
const filterPromises = array.map(item =>
268
Q.resolve(item).then(predicate).then(passed => ({ item, passed }))
269
);
270
271
return Q.all(filterPromises).then(results =>
272
results.filter(result => result.passed).map(result => result.item)
273
);
274
}
275
276
// Promise-based reduce function
277
function promiseReduce(array, reducer, initialValue) {
278
return array.reduce((promise, item) => {
279
return promise.then(accumulator =>
280
Q.all([accumulator, item]).spread(reducer)
281
);
282
}, Q.resolve(initialValue));
283
}
284
285
// Usage examples
286
const numbers = [1, 2, 3, 4, 5];
287
288
// Map with async operation
289
promiseMap(numbers, num => Q.delay(num * 2, 50))
290
.then(doubled => console.log("Doubled:", doubled));
291
292
// Filter with async predicate
293
promiseFilter(numbers, num => Q.delay(num > 3, 10))
294
.then(filtered => console.log("Filtered:", filtered));
295
296
// Reduce with async reducer
297
promiseReduce(numbers, (acc, num) => Q.delay(acc + num, 10), 0)
298
.then(sum => console.log("Sum:", sum));
299
```
300
301
### Composition Utilities
302
303
Utilities for composing promise-based functions.
304
305
```javascript
306
const Q = require("q");
307
308
// Function composition for promises
309
function composeAsync(...functions) {
310
return function(input) {
311
return functions.reduce((promise, fn) => {
312
return promise.then(fn);
313
}, Q.resolve(input));
314
};
315
}
316
317
// Pipeline for sequential processing
318
function pipeline(...stages) {
319
return function(input) {
320
return stages.reduce((promise, stage) => {
321
return promise.then(stage);
322
}, Q.resolve(input));
323
};
324
}
325
326
// Usage
327
const processData = composeAsync(
328
data => Q.delay(data.trim(), 10),
329
data => Q.delay(data.toUpperCase(), 10),
330
data => Q.delay(`Processed: ${data}`, 10)
331
);
332
333
processData(" hello world ")
334
.then(result => console.log(result)); // "Processed: HELLO WORLD"
335
336
// Data processing pipeline
337
const dataPipeline = pipeline(
338
data => validateInput(data),
339
data => enrichWithMetadata(data),
340
data => applyBusinessRules(data),
341
data => formatForOutput(data)
342
);
343
344
dataPipeline(rawData)
345
.then(processedData => console.log("Pipeline result:", processedData))
346
.catch(error => console.error("Pipeline failed:", error));
347
```