Hien's Home
View RSS feed

[Snippet] - Promise Implementation

Published on

The code below is the custom implementation of JavaScript Promise

1const PromiseState = {
2 pending: "pending",
3 fulfilled: "fulfilled",
4 rejected: "rejected",
5};
6
7class MyPromise {
8 #state = PromiseState.pending;
9 #value = null;
10 #fulfilledCallbacks = [];
11 #rejectedCallbacks = [];
12
13 get value() {
14 return this.#value;
15 }
16
17 get state() {
18 return this.#state;
19 }
20
21 constructor(executorFunction) {
22 try {
23 executorFunction(
24 (value) => this.#resolve(value),
25 (value) => this.#reject(value)
26 );
27 } catch (error) {
28 this.#reject(error);
29 }
30 }
31
32 #resolve(value) {
33 if (this.#state !== PromiseState.pending) return;
34
35 this.#value = value;
36 this.#state = PromiseState.fulfilled;
37 this.#fulfilledCallbacks.forEach((cb) => cb());
38 }
39
40 #reject(value) {
41 if (this.#state !== PromiseState.pending) return;
42
43 this.#value = value;
44 this.#state = PromiseState.rejected;
45 this.#rejectedCallbacks.forEach((cb) => cb());
46 }
47
48 finally(callback) {
49 return new MyPromise((resolve, reject) => {
50 const doFulfillment = () => {
51 if (!callback) return;
52
53 queueMicrotask(() => {
54 try {
55 callback();
56 resolve(this.#value);
57 } catch (error) {
58 reject(error);
59 }
60 });
61 };
62
63 const doRejection = () => {
64 if (!callback) return;
65
66 queueMicrotask(() => {
67 try {
68 callback();
69 reject(this.#value);
70 } catch (error) {
71 reject(error);
72 }
73 });
74 };
75
76 switch (this.#state) {
77 case PromiseState.pending:
78 this.#fulfilledCallbacks.push(doFulfillment);
79 this.#rejectedCallbacks.push(doRejection);
80 break;
81 case PromiseState.fulfilled:
82 doFulfillment();
83 break;
84 case PromiseState.rejected:
85 doRejection();
86 break;
87 default:
88 throw new Error(`Unknown promise state ${this.#state}`);
89 }
90 });
91 }
92
93 then(onFulfilled, onRejected) {
94 return new MyPromise((resolve, reject) => {
95 const doFulfillment = () => {
96 if (!onFulfilled) return resolve(this.#value);
97
98 queueMicrotask(() => {
99 try {
100 const result = onFulfilled(this.#value);
101 resolve(result);
102 } catch (error) {
103 reject(error);
104 }
105 });
106 };
107 const doRejection = () => {
108 if (!onRejected) return reject(this.#value);
109
110 queueMicrotask(() => {
111 try {
112 const result = onRejected(this.#value);
113 resolve(result);
114 } catch (error) {
115 reject(error);
116 }
117 });
118 };
119
120 switch (this.#state) {
121 case PromiseState.pending:
122 this.#fulfilledCallbacks.push(doFulfillment);
123 this.#rejectedCallbacks.push(doRejection);
124 break;
125 case PromiseState.fulfilled:
126 doFulfillment();
127 break;
128 case PromiseState.rejected:
129 doRejection();
130 break;
131 default:
132 throw new Error(`Unknown promise state ${this.#state}`);
133 }
134 });
135 }
136
137 catch(onRejected) {
138 return this.then(null, onRejected);
139 }
140}