promise-logic 2.4.4 → 2.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +122 -191
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,227 +1,158 @@
|
|
|
1
|
-
# Promise Logic - A Declarative Promise Library Based on Logic Gates
|
|
2
1
|
|
|
3
|
-
This description might sound a bit awkward, but it essentially means a Promise wrapper library designed based on the concept of logic gates, providing a more declarative syntax. However, promiseLogic's implementation is based on promises, so we can say it's a promise-based wrapper library.
|
|
4
2
|
|
|
5
|
-
This design is really interesting. I spent a lot of time thinking about it and realized that promise state machines ultimately have only two outcomes: either fulfilled or rejected. This state design can be abstracted using boolean operations, allowing for declarative writing that reduces our memory burden and mental load during development. Let's look at some examples.
|
|
6
3
|
|
|
7
|
-
|
|
4
|
+
### **1. Core Philosophy**
|
|
8
5
|
|
|
9
|
-
|
|
6
|
+
**Replace API Memory with Logical Concepts**
|
|
7
|
+
The design philosophy of `promise-logic` is: **Developers should focus on business logic, not the details of Promise APIs**.
|
|
8
|
+
Traditional Promise combinations (such as `Promise.all`, `Promise.race`) have naming and semantics that are not intuitive enough, especially in complex asynchronous scenarios where code readability rapidly declines.
|
|
9
|
+
`promise-logic` abstracts asynchronous combinations into logical operations like `and`, `or`, `xor` through the concept of **Logic Gates**, making code semantically clear and self-explanatory.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
npm install promise-logic
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
```javascript
|
|
16
|
-
import PromiseLogic from 'promise-logic';
|
|
17
|
-
|
|
18
|
-
// Native Promise
|
|
19
|
-
const promise = Promise.all([
|
|
20
|
-
Promise.resolve(1),
|
|
21
|
-
Promise.resolve(2),
|
|
22
|
-
Promise.resolve(3)
|
|
23
|
-
]);
|
|
24
|
-
|
|
25
|
-
// Promise Logic -- AND gate
|
|
26
|
-
const promiseLogic = PromiseLogic.and([
|
|
27
|
-
Promise.resolve(1),
|
|
28
|
-
Promise.resolve(2),
|
|
29
|
-
Promise.resolve(3)
|
|
30
|
-
]); // [1,2,3]
|
|
31
|
-
|
|
32
|
-
// This syntax is more semantic, easier to understand, reduces team communication costs, and is more friendly to learners
|
|
33
|
-
|
|
34
|
-
// Native promise
|
|
35
|
-
const promise = Promise.any([
|
|
36
|
-
Promise.resolve(1),
|
|
37
|
-
Promise.reject(2),
|
|
38
|
-
Promise.resolve(3)
|
|
39
|
-
]); // 1
|
|
40
|
-
|
|
41
|
-
// Promise Logic -- OR gate
|
|
42
|
-
const promiseLogicOr = PromiseLogic.or([
|
|
43
|
-
Promise.resolve(1),
|
|
44
|
-
Promise.reject(2),
|
|
45
|
-
Promise.resolve(3)
|
|
46
|
-
]); // 1
|
|
47
|
-
|
|
48
|
-
// The result of or is consistent with native promise.any, but from here, I think you should see the pattern, and there's more to it
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
It also supports TypeScript syntax:
|
|
52
|
-
|
|
53
|
-
```javascript
|
|
54
|
-
const promiseLogic =
|
|
55
|
-
PromiseLogic.and <
|
|
56
|
-
number >
|
|
57
|
-
[Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]; // [1,2,3]
|
|
58
|
-
|
|
59
|
-
const promiseLogicOr =
|
|
60
|
-
PromiseLogic.or <
|
|
61
|
-
string >
|
|
62
|
-
[
|
|
63
|
-
Promise.resolve('data 1'),
|
|
64
|
-
Promise.reject('error 2'),
|
|
65
|
-
Promise.resolve('data 3')
|
|
66
|
-
]; // 'data 1'
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
#### We can also create flexible combinations for complex request resources
|
|
70
|
-
|
|
71
|
-
```javascript
|
|
72
|
-
// OR + AND
|
|
73
|
-
// Suppose we have a scenario where we want to get data from multiple data sources, need the fastest request result, but also need all requests in one request group to succeed before returning a result. Implementing this with native Promise would be extremely complex
|
|
74
|
-
|
|
75
|
-
// Now we can implement it like this:
|
|
76
|
-
const result = await PromiseLogic.or([
|
|
77
|
-
PromiseLogic.and([
|
|
78
|
-
// Request group 1
|
|
79
|
-
fetch('/api/data1'), // Request 1
|
|
80
|
-
fetch('/api/data2') // Request 2
|
|
81
|
-
]),
|
|
82
|
-
PromiseLogic.and([
|
|
83
|
-
// Request group 2
|
|
84
|
-
fetch('/api/data3'), // Request 3
|
|
85
|
-
fetch('/api/data4') // Request 4
|
|
86
|
-
])
|
|
87
|
-
]); // Result: [fetch('/api/data1'),fetch('/api/data2')] or [fetch('/api/data3'),fetch('/api/data4')] or error
|
|
88
|
-
|
|
89
|
-
// This returns the fastest successful result, and this successful result must come from a request group where all requests in the AND combination have succeeded
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
Of course, there are other logic gates like exclusive OR, NAND, NOR, XNOR, majority, etc. Their implementations are all very simple, so I won't introduce them one by one. They all use the same pattern but have different logical semantics, so you can choose which one to use based on your scenario.
|
|
11
|
+
---
|
|
93
12
|
|
|
94
|
-
|
|
13
|
+
### **2. Features**
|
|
95
14
|
|
|
96
|
-
|
|
15
|
+
1. **Logical Semantics**
|
|
16
|
+
- `and`: All tasks must succeed (equivalent to `Promise.all`)
|
|
17
|
+
- `or`: At least one task succeeds (equivalent to `Promise.race`)
|
|
18
|
+
- `xor`: **Exactly one task succeeds** (no direct equivalent in traditional Promise)
|
|
19
|
+
- `nand`: All tasks fail
|
|
97
20
|
|
|
98
|
-
|
|
21
|
+
- `not`: Inverts the result of a single Promise
|
|
22
|
+
- `majority`: Most tasks succeed
|
|
99
23
|
|
|
100
|
-
|
|
24
|
+
2. **Zero Dependencies**
|
|
25
|
+
Only depends on native Promise, no additional runtime dependencies.
|
|
101
26
|
|
|
102
|
-
|
|
27
|
+
3. **Full Test Coverage**
|
|
28
|
+
All logic gates have undergone rigorous unit testing to ensure behavior meets expectations.
|
|
103
29
|
|
|
104
|
-
|
|
30
|
+
4. **Clear Error Classification**
|
|
31
|
+
- `PromiseLogicError` unified error type
|
|
32
|
+
- `error.type` distinguishes specific logical errors (e.g., `'XOR_ERROR'`)
|
|
105
33
|
|
|
106
|
-
|
|
34
|
+
---
|
|
107
35
|
|
|
108
|
-
|
|
109
|
-
- `PromiseLogic.race`
|
|
36
|
+
### **3. Installation**
|
|
110
37
|
|
|
111
|
-
|
|
38
|
+
```bash
|
|
39
|
+
npm install promise-logic
|
|
40
|
+
```
|
|
112
41
|
|
|
113
|
-
|
|
42
|
+
---
|
|
114
43
|
|
|
115
|
-
|
|
44
|
+
### **4. Quick Start**
|
|
116
45
|
|
|
46
|
+
#### Example: Primary/Backup Service Call (XOR Scenario)
|
|
117
47
|
```javascript
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
// Managing device connection state
|
|
121
|
-
class ConnectionManager {
|
|
122
|
-
constructor() {
|
|
123
|
-
this.connectionState = PromiseLogic.createFlipFlop(false); // Initial disconnected state
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
async connect() {
|
|
127
|
-
console.log('Connecting...');
|
|
128
|
-
// Simulate connection process
|
|
129
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
130
|
-
await this.connectionState.set(true); // Set connected state
|
|
131
|
-
console.log('Connected!');
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async disconnect() {
|
|
135
|
-
console.log('Disconnecting...');
|
|
136
|
-
await this.connectionState.set(false); // Set disconnected state
|
|
137
|
-
console.log('Disconnected!');
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
async waitForConnection() {
|
|
141
|
-
console.log('Waiting for connection...');
|
|
142
|
-
await this.connectionState.waitFor(true); // Wait until connected
|
|
143
|
-
console.log('Connection established!');
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async monitorConnection() {
|
|
147
|
-
// Monitor state changes
|
|
148
|
-
while (true) {
|
|
149
|
-
const newState = await this.connectionState.waitForChange();
|
|
150
|
-
console.log('Connection state changed to:', newState ? 'connected' : 'disconnected');
|
|
151
|
-
if (!newState) break; // Exit if disconnected
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
48
|
+
import PromiseLogic from 'promise-logic';
|
|
155
49
|
|
|
156
|
-
//
|
|
157
|
-
const
|
|
50
|
+
// Primary service call
|
|
51
|
+
const primary = fetch('https://api.main.com/data');
|
|
52
|
+
// Backup service call
|
|
53
|
+
const backup = fetch('https://api.backup.com/data');
|
|
54
|
+
|
|
55
|
+
// Execute XOR logic: exactly one success
|
|
56
|
+
PromiseLogic.xor([primary, backup])
|
|
57
|
+
.then(result => {
|
|
58
|
+
console.log('Successfully fetched data:', result);
|
|
59
|
+
})
|
|
60
|
+
.catch(error => {
|
|
61
|
+
if (error.type === 'XOR_ERROR') {
|
|
62
|
+
console.error('Both primary and backup services succeeded or failed, which does not meet XOR semantics');
|
|
63
|
+
} else {
|
|
64
|
+
console.error('Network error:', error);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
```
|
|
158
68
|
|
|
159
|
-
|
|
160
|
-
|
|
69
|
+
#### Example: Majority Decision (Majority Scenario)
|
|
70
|
+
```javascript
|
|
71
|
+
import PromiseLogic from 'promise-logic';
|
|
161
72
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
73
|
+
const services = [
|
|
74
|
+
fetch('https://api.node1.com/vote'),
|
|
75
|
+
fetch('https://api.node2.com/vote'),
|
|
76
|
+
fetch('https://api.node3.com/vote')
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
PromiseLogic.majority(services)
|
|
80
|
+
.then(results => {
|
|
81
|
+
console.log('Majority of services returned success:', results);
|
|
82
|
+
})
|
|
83
|
+
.catch(error => {
|
|
84
|
+
console.error('Majority of services failed:', error);
|
|
85
|
+
});
|
|
86
|
+
```
|
|
165
87
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
88
|
+
```typescript
|
|
89
|
+
import PromiseLogic from 'promise-logic/typescript';
|
|
90
|
+
|
|
91
|
+
const services = [
|
|
92
|
+
fetch('https://api.node1.com/vote'),
|
|
93
|
+
fetch('https://api.node2.com/vote'),
|
|
94
|
+
fetch('https://api.node3.com/vote')
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
PromiseLogic.majority<Response>(services)
|
|
98
|
+
.then(results => {
|
|
99
|
+
console.log('Majority of services returned success:', results);
|
|
100
|
+
})
|
|
101
|
+
.catch(error => {
|
|
102
|
+
console.error('Majority of services failed:', error);
|
|
103
|
+
});
|
|
170
104
|
```
|
|
171
105
|
|
|
172
|
-
|
|
106
|
+
---
|
|
173
107
|
|
|
174
|
-
API
|
|
108
|
+
### **5. API Reference**
|
|
175
109
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
110
|
+
| API | Description |
|
|
111
|
+
| :--------- | :-------------------------------------------------------------------------- |
|
|
112
|
+
| `and` | All Promises succeed, returns result array; any failure causes overall failure. |
|
|
113
|
+
| `or` | At least one Promise succeeds, returns first success result; all failures cause overall failure. |
|
|
114
|
+
| `xor` | **Exactly one Promise succeeds**, returns that result; otherwise throws `XOR_ERROR`. |
|
|
115
|
+
| `nand` | All Promises fail, returns error array; any success causes overall failure. |
|
|
116
|
+
| `not` | Inverts the result of a single Promise |
|
|
117
|
+
| `majority` | More than half of Promises succeed, returns success result array; otherwise overall failure. |
|
|
179
118
|
|
|
180
|
-
|
|
119
|
+
---
|
|
181
120
|
|
|
182
|
-
|
|
121
|
+
### **6. Real-world Application Scenarios**
|
|
183
122
|
|
|
184
|
-
**
|
|
185
|
-
|
|
123
|
+
1. **Primary/Backup Service Calls**
|
|
124
|
+
- Use `xor` to ensure **exactly one service responds**, avoiding duplicate processing.
|
|
125
|
+
2. **Distributed Decision Making**
|
|
126
|
+
- Use `majority` to implement majority consensus (e.g., distributed voting).
|
|
127
|
+
3. **Resource Competition**
|
|
128
|
+
- Use `or` to get the first available resource (e.g., CDN node selection).
|
|
129
|
+
- Use `not` to check if a resource is available.
|
|
130
|
+
4. **Full-link Validation**
|
|
131
|
+
- Use `and` to ensure all dependent services succeed (e.g., order creation).
|
|
186
132
|
|
|
187
|
-
|
|
188
|
-
- `set(newState: boolean)`: Sets the new state and returns Promise<boolean>
|
|
189
|
-
- `toggle()`: Toggles the current state and returns Promise<boolean>
|
|
190
|
-
- `waitForChange()`: Returns a Promise that resolves when the state changes
|
|
191
|
-
- `waitFor(targetState: boolean)`: Returns a Promise that resolves when the state matches the target
|
|
133
|
+
---
|
|
192
134
|
|
|
193
|
-
###
|
|
135
|
+
### **7. Contribution Guide**
|
|
194
136
|
|
|
195
|
-
|
|
137
|
+
1. **Development Environment**
|
|
138
|
+
```bash
|
|
139
|
+
git clone https://github.com/haowhite/promise-logic.git
|
|
140
|
+
cd promise-logic
|
|
141
|
+
npm install
|
|
142
|
+
```
|
|
143
|
+
2. **Testing**
|
|
144
|
+
```bash
|
|
145
|
+
npm test
|
|
146
|
+
```
|
|
147
|
+
3. **Commit Guidelines**
|
|
148
|
+
- Commit messages must include prefixes like `feat:` (new feature), `fix:` (bug fix), `docs:` (documentation).
|
|
149
|
+
- Pull Requests must include test cases.
|
|
196
150
|
|
|
197
|
-
|
|
151
|
+
---
|
|
198
152
|
|
|
199
|
-
|
|
200
|
-
- `prefix` (string, optional): String to prepend to all method names
|
|
201
|
-
- `suffix` (string, optional): String to append to all method names
|
|
202
|
-
- `rename` (Record<string, string>, optional): Mapping of original method names to new names
|
|
153
|
+
### **8. Resource Links**
|
|
203
154
|
|
|
204
|
-
**
|
|
205
|
-
|
|
155
|
+
- **GitHub Repository**:[https://github.com/xier123456/promise-logic](https://github.com/xier123456/promise-logic)
|
|
156
|
+
- **npm Package**:[https://www.npmjs.com/package/promise-logic](https://www.npmjs.com/package/promise-logic)
|
|
157
|
+
- **Issue Tracking**:[GitHub Issues](https://github.com/xier123456/promise-logic/issues)
|
|
206
158
|
|
|
207
|
-
```javascript
|
|
208
|
-
// Basic usage - returns all methods with default names
|
|
209
|
-
const logic = createPromiseLogic();
|
|
210
|
-
|
|
211
|
-
// Combined options
|
|
212
|
-
const combined = createPromiseLogic({
|
|
213
|
-
prefix: 'async', // Add prefix
|
|
214
|
-
suffix: 'Op', // Add suffix
|
|
215
|
-
rename: {
|
|
216
|
-
// API renaming
|
|
217
|
-
and: 'Conjunction',
|
|
218
|
-
or: 'Disjunction'
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
// Call combined method (async)+ (Conjunction) + (Op)
|
|
223
|
-
const result = await logic.asycnConjunctionOp([
|
|
224
|
-
fetch('/api/data1'),
|
|
225
|
-
fetch('/api/data2')
|
|
226
|
-
]);
|
|
227
|
-
```
|
package/package.json
CHANGED