Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 5a3ca51

Browse files
added folder class promise
1 parent 8fa59bb commit 5a3ca51

File tree

6 files changed

+7440
-0
lines changed

6 files changed

+7440
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 WebDevSimplified
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
const STATE = {
2+
FULFILLED: "fulfilled",
3+
REJECTED: "rejected",
4+
PENDING: "pending",
5+
}
6+
7+
class MyPromise {
8+
#thenCbs = []
9+
#catchCbs = []
10+
#state = STATE.PENDING
11+
#value
12+
#onSuccessBind = this.#onSuccess.bind(this)
13+
#onFailBind = this.#onFail.bind(this)
14+
15+
constructor(cb) {
16+
try {
17+
cb(this.#onSuccessBind, this.#onFailBind)
18+
} catch (e) {
19+
this.#onFail(e)
20+
}
21+
}
22+
23+
#runCallbacks() {
24+
if (this.#state === STATE.FULFILLED) {
25+
this.#thenCbs.forEach(callback => {
26+
callback(this.#value)
27+
})
28+
29+
this.#thenCbs = []
30+
}
31+
32+
if (this.#state === STATE.REJECTED) {
33+
this.#catchCbs.forEach(callback => {
34+
callback(this.#value)
35+
})
36+
37+
this.#catchCbs = []
38+
}
39+
}
40+
41+
#onSuccess(value) {
42+
queueMicrotask(() => {
43+
if (this.#state !== STATE.PENDING) return
44+
45+
if (value instanceof MyPromise) {
46+
value.then(this.#onSuccessBind, this.#onFailBind)
47+
return
48+
}
49+
50+
this.#value = value
51+
this.#state = STATE.FULFILLED
52+
this.#runCallbacks()
53+
})
54+
}
55+
56+
#onFail(value) {
57+
queueMicrotask(() => {
58+
if (this.#state !== STATE.PENDING) return
59+
60+
if (value instanceof MyPromise) {
61+
value.then(this.#onSuccessBind, this.#onFailBind)
62+
return
63+
}
64+
65+
if (this.#catchCbs.length === 0) {
66+
throw new UncaughtPromiseError(value)
67+
}
68+
69+
this.#value = value
70+
this.#state = STATE.REJECTED
71+
this.#runCallbacks()
72+
})
73+
}
74+
75+
then(thenCb, catchCb) {
76+
return new MyPromise((resolve, reject) => {
77+
this.#thenCbs.push(result => {
78+
if (thenCb == null) {
79+
resolve(result)
80+
return
81+
}
82+
83+
try {
84+
resolve(thenCb(result))
85+
} catch (error) {
86+
reject(error)
87+
}
88+
})
89+
90+
this.#catchCbs.push(result => {
91+
if (catchCb == null) {
92+
reject(result)
93+
return
94+
}
95+
96+
try {
97+
resolve(catchCb(result))
98+
} catch (error) {
99+
reject(error)
100+
}
101+
})
102+
103+
this.#runCallbacks()
104+
})
105+
}
106+
107+
catch(cb) {
108+
return this.then(undefined, cb)
109+
}
110+
111+
finally(cb) {
112+
return this.then(
113+
result => {
114+
cb()
115+
return result
116+
},
117+
result => {
118+
cb()
119+
throw result
120+
}
121+
)
122+
}
123+
124+
static resolve(value) {
125+
return new Promise(resolve => {
126+
resolve(value)
127+
})
128+
}
129+
130+
static reject(value) {
131+
return new Promise((resolve, reject) => {
132+
reject(value)
133+
})
134+
}
135+
136+
static all(promises) {
137+
const results = []
138+
let completedPromises = 0
139+
return new MyPromise((resolve, reject) => {
140+
for (let i = 0; i < promises.length; i++) {
141+
const promise = promises[i]
142+
promise
143+
.then(value => {
144+
completedPromises++
145+
results[i] = value
146+
if (completedPromises === promises.length) {
147+
resolve(results)
148+
}
149+
})
150+
.catch(reject)
151+
}
152+
})
153+
}
154+
155+
static allSettled(promises) {
156+
const results = []
157+
let completedPromises = 0
158+
return new MyPromise(resolve => {
159+
for (let i = 0; i < promises.length; i++) {
160+
const promise = promises[i]
161+
promise
162+
.then(value => {
163+
results[i] = { status: STATE.FULFILLED, value }
164+
})
165+
.catch(reason => {
166+
results[i] = { status: STATE.REJECTED, reason }
167+
})
168+
.finally(() => {
169+
completedPromises++
170+
if (completedPromises === promises.length) {
171+
resolve(results)
172+
}
173+
})
174+
}
175+
})
176+
}
177+
178+
static race(promises) {
179+
return new MyPromise((resolve, reject) => {
180+
promises.forEach(promise => {
181+
promise.then(resolve).catch(reject)
182+
})
183+
})
184+
}
185+
186+
static any(promises) {
187+
const errors = []
188+
let rejectedPromises = 0
189+
return new MyPromise((resolve, reject) => {
190+
for (let i = 0; i < promises.length; i++) {
191+
const promise = promises[i]
192+
promise.then(resolve).catch(value => {
193+
rejectedPromises++
194+
errors[i] = value
195+
if (rejectedPromises === promises.length) {
196+
reject(new AggregateError(errors, "All promises were rejected"))
197+
}
198+
})
199+
}
200+
})
201+
}
202+
}
203+
204+
class UncaughtPromiseError extends Error {
205+
constructor(error) {
206+
super(error)
207+
208+
this.stack = `(in promise) ${error.stack}`
209+
}
210+
}
211+
212+
module.exports = MyPromise
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
const MyPromise = require("./MyPromise.js")
2+
// const MyPromise = Promise
3+
4+
const DEFAULT_VALUE = "default"
5+
6+
describe("then", () => {
7+
it("with no chaining", () => {
8+
return promise().then(v => expect(v).toEqual(DEFAULT_VALUE))
9+
})
10+
11+
it("with multiple thens for same promise", () => {
12+
const checkFunc = v => expect(v).toEqual(DEFAULT_VALUE)
13+
const mainPromise = promise()
14+
const promise1 = mainPromise.then(checkFunc)
15+
const promise2 = mainPromise.then(checkFunc)
16+
return Promise.allSettled([promise1, promise2])
17+
})
18+
19+
it("with then and catch", () => {
20+
const checkFunc = v => expect(v).toEqual(DEFAULT_VALUE)
21+
const failFunc = v => expect(1).toEqual(2)
22+
const resolvePromise = promise().then(checkFunc, failFunc)
23+
const rejectPromise = promise({ fail: true }).then(failFunc, checkFunc)
24+
return Promise.allSettled([resolvePromise, rejectPromise])
25+
})
26+
27+
it("with chaining", () => {
28+
return promise({ value: 3 })
29+
.then(v => v * 4)
30+
.then(v => expect(v).toEqual(12))
31+
})
32+
})
33+
34+
describe("catch", () => {
35+
it("with no chaining", () => {
36+
return promise({ fail: true }).catch(v => expect(v).toEqual(DEFAULT_VALUE))
37+
})
38+
39+
it("with multiple catches for same promise", () => {
40+
const checkFunc = v => expect(v).toEqual(DEFAULT_VALUE)
41+
const mainPromise = promise({ fail: true })
42+
const promise1 = mainPromise.catch(checkFunc)
43+
const promise2 = mainPromise.catch(checkFunc)
44+
return Promise.allSettled([promise1, promise2])
45+
})
46+
47+
it("with chaining", () => {
48+
return promise({ value: 3 })
49+
.then(v => {
50+
throw v * 4
51+
})
52+
.catch(v => expect(v).toEqual(12))
53+
})
54+
})
55+
56+
describe("finally", () => {
57+
it("with no chaining", () => {
58+
const checkFunc = v => v => expect(v).toBeUndefined()
59+
const successPromise = promise().finally(checkFunc)
60+
const failPromise = promise({ fail: true }).finally(checkFunc)
61+
return Promise.allSettled([successPromise, failPromise])
62+
})
63+
64+
it("with multiple finallys for same promise", () => {
65+
const checkFunc = v => expect(v).toBeUndefined()
66+
const mainPromise = promise()
67+
const promise1 = mainPromise.finally(checkFunc)
68+
const promise2 = mainPromise.finally(checkFunc)
69+
return Promise.allSettled([promise1, promise2])
70+
})
71+
72+
it("with chaining", () => {
73+
const checkFunc = v => v => expect(v).toBeUndefined()
74+
const successPromise = promise()
75+
.then(v => v)
76+
.finally(checkFunc)
77+
const failPromise = promise({ fail: true })
78+
.then(v => v)
79+
.finally(checkFunc)
80+
return Promise.allSettled([successPromise, failPromise])
81+
})
82+
})
83+
84+
describe("static methods", () => {
85+
it("resolve", () => {
86+
return MyPromise.resolve(DEFAULT_VALUE).then(v =>
87+
expect(v).toEqual(DEFAULT_VALUE)
88+
)
89+
})
90+
91+
it("reject", () => {
92+
return MyPromise.reject(DEFAULT_VALUE).catch(v =>
93+
expect(v).toEqual(DEFAULT_VALUE)
94+
)
95+
})
96+
97+
describe("all", () => {
98+
it("with success", () => {
99+
return MyPromise.all([promise({ value: 1 }), promise({ value: 2 })]).then(
100+
v => expect(v).toEqual([1, 2])
101+
)
102+
})
103+
104+
it("with fail", () => {
105+
return MyPromise.all([promise(), promise({ fail: true })]).catch(v =>
106+
expect(v).toEqual(DEFAULT_VALUE)
107+
)
108+
})
109+
})
110+
111+
it("allSettled", () => {
112+
return MyPromise.allSettled([promise(), promise({ fail: true })]).then(v =>
113+
expect(v).toEqual([
114+
{ status: "fulfilled", value: DEFAULT_VALUE },
115+
{ status: "rejected", reason: DEFAULT_VALUE },
116+
])
117+
)
118+
})
119+
120+
describe("race", () => {
121+
it("with success", () => {
122+
return MyPromise.race([
123+
promise({ value: 1 }),
124+
promise({ value: 2 }),
125+
]).then(v => expect(v).toEqual(1))
126+
})
127+
128+
it("with fail", () => {
129+
return MyPromise.race([
130+
promise({ fail: true, value: 1 }),
131+
promise({ fail: true, value: 2 }),
132+
]).catch(v => expect(v).toEqual(1))
133+
})
134+
})
135+
136+
describe("any", () => {
137+
it("with success", () => {
138+
return MyPromise.any([promise({ value: 1 }), promise({ value: 2 })]).then(
139+
v => expect(v).toEqual(1)
140+
)
141+
})
142+
143+
it("with fail", () => {
144+
return MyPromise.any([
145+
promise({ fail: true, value: 1 }),
146+
promise({ value: 2 }),
147+
]).catch(e => expect(e.errors).toEqual([1, 2]))
148+
})
149+
})
150+
})
151+
152+
function promise({ value = DEFAULT_VALUE, fail = false } = {}) {
153+
return new MyPromise((resolve, reject) => {
154+
fail ? reject(value) : resolve(value)
155+
})
156+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /