-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpromise-class.js
161 lines (145 loc) · 4.02 KB
/
promise-class.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
const STATUS = {
PENDING: 'pending',
FULFILLED: 'fulfilled',
REJECTED: 'rejected',
}
addToTaskQueue = (task) => setTimeout(task, 0)
isEmpty = (arr) => Array.isArray(arr) && arr.length === 0
class MyPromise {
constructor(executor) {
this.status = STATUS.PENDING
this.value = null
this.error = null
this.fulfilledTasks = []
executor(MyPromise.resolve.bind(this), MyPromise.reject.bind(this))
}
static resolve(value) {
if (this.status !== STATUS.PENDING) {
return this
}
this.value = value
this.status = STATUS.FULFILLED
this.fulfilledTasks.forEach((task) => {
addToTaskQueue(task)
})
}
static reject(error) {
if (this.status !== STATUS.PENDING) {
return this
}
this.error = error
this.status = STATUS.REJECTED
if (this.rejectedFunc) {
addToTaskQueue(this.rejectedFunc)
}
return this // should return new Promise of which status is pending
}
scheduleOnRejectedFunc = (onRejected) => {
if (this.rejectedFunc) return
const rejectedTask = () => {
this.value = onRejected(this.error)
this.status = STATUS.PENDING
this.fulfilledTasks.forEach((task) => {
addToTaskQueue(task)
})
}
this.rejectedFunc = rejectedTask
}
then(onFulfilled, onRejected) {
console.log('in then, ', this.status)
const fulfilledTask = () => {
this.value = onFulfilled(this.value)
}
switch (this.status) {
case STATUS.PENDING: {
this.fulfilledTasks.push(fulfilledTask)
if (onRejected && typeof onRejected === 'function') {
scheduleOnRejectedFunc(onRejected) // value와 error 구분할 필요가 없다?
}
return this
}
case STATUS.FULFILLED: {
addToTaskQueue(fulfilledTask)
return this
}
case STATUS.REJECTED: {
if (onRejected) {
addToTaskQueue(() => onRejected(this.error))
}
return this
}
}
}
catch(onRejected) {
console.log('in catch', this.status)
const rejectedTask = () => onRejected(this.error)
switch (this.status) {
case STATUS.PENDING: {
if (onRejected && typeof onRejected === 'function') {
this.scheduleOnRejectedFunc(onRejected)
}
return this
}
case STATUS.FULFILLED: {
return this
}
case STATUS.REJECTED: {
addToTaskQueue(rejectedTask)
return this
}
}
}
}
// const p = new MyPromise((resolve, reject) => {
// setTimeout(() => {
// console.log('start')
// resolve(1)
// }, 5000)
// })
// .then((value) => {
// console.log('then 1.', value)
// return value + 1
// })
// .then((value) => {
// console.log('then 2.', value)
// })
// .then(() => {
// console.log('finally', this)
// })
const p2 = new MyPromise((_, reject) => {
setTimeout(() => reject('error!'), 5000)
})
.then((value) => console.log('then 1', value))
.catch(1)
.catch((err) => {
console.log('catched 1', err)
return 1
})
.catch((err) => console.log('catched 2', err))
.then((value) => console.log('then 2', value))
// test
// 1. Resolve
// - then 체이닝이 가능한가
// - then을 통해 반환되는 값이 올바르게 전달되는가
// 2. Reject
// - reject된 경우
// 1) 중간 then (onFulfilled) 함수는 호출되지 않는다
// 2) 가장 가까운 catch가 호출된다
// 3) 호출된 catch 이후 catch 메소드는 호출되지 않는다.
// 3. throw error: 중간에 에러가 발생한 경우
// - then 체이닝이 올바르게 동작한다 (resolve와 동일)
// - 에러 발생 후 catch에 에러가 잡힌다 (reject와 동일)
// - 에러 발생 후 catch에서 반환값이 있는 경우 동일하게 then 체이닝 가능
// new Promise((_, reject) => {
// setTimeout(() => reject('error!'), 5000)
// })
// .catch(1)
// .catch((err) => {
// console.log('catched: ', err)
// return 1
// })
// .catch((err) => {
// console.log(err)
// return 2
// })
// .then((value) => console.log(value))