@@ -8,20 +8,11 @@ is of actual JavaScript `Error` type, you should use `JSPromise<JSValue, JSValue
8
8
This doesn't 100% match the JavaScript API, as `then` overload with two callbacks is not available.
9
9
It's impossible to unify success and failure types from both callbacks in a single returned promise
10
10
without type erasure. You should chain `then` and `catch` in those cases to avoid type erasure.
11
-
12
- **IMPORTANT**: instances of this class must have the same lifetime as the actual `Promise` object in
13
- the JavaScript environment, because callback handlers will be deallocated when `JSPromise.deinit` is
14
- executed.
15
-
16
- If the actual `Promise` object in JavaScript environment lives longer than this `JSPromise`, it may
17
- attempt to call a deallocated `JSClosure`.
18
11
*/
19
12
public final class JSPromise < Success, Failure> : ConvertibleToJSValue , ConstructibleFromJSValue {
20
13
/// The underlying JavaScript `Promise` object.
21
14
public let jsObject : JSObject
22
15
23
- private var callbacks = [ JSClosure] ( )
24
-
25
16
/// The underlying JavaScript `Promise` object wrapped as `JSValue`.
26
17
public func jsValue( ) -> JSValue {
27
18
. object( jsObject)
@@ -52,39 +43,37 @@ public final class JSPromise<Success, Failure>: ConvertibleToJSValue, Constructi
52
43
/** Schedules the `success` closure to be invoked on sucessful completion of `self`.
53
44
*/
54
45
public func then( success: @escaping ( ) -> ( ) ) {
55
- let closure = JSClosure { _ in success ( ) }
56
- callbacks. append ( closure)
46
+ let closure = JSOneshotClosure { _ in
47
+ success ( )
48
+ return . undefined
49
+ }
57
50
_ = jsObject. then!( closure)
58
51
}
59
52
60
53
/** Schedules the `failure` closure to be invoked on either successful or rejected completion of
61
54
`self`.
62
55
*/
63
56
public func finally( successOrFailure: @escaping ( ) -> ( ) ) -> Self {
64
- let closure = JSClosure { _ in
57
+ let closure = JSOneshotClosure { _ in
65
58
successOrFailure ( )
59
+ return . undefined
66
60
}
67
- callbacks. append ( closure)
68
61
return . init( unsafe: jsObject. finally!( closure) . object!)
69
62
}
70
-
71
- deinit {
72
- callbacks. forEach { $0. release ( ) }
73
- }
74
63
}
75
64
76
65
extension JSPromise where Success == ( ) , Failure == Never {
77
66
/** Creates a new `JSPromise` instance from a given `resolver` closure. `resolver` takes
78
67
a closure that your code should call to resolve this `JSPromise` instance.
79
68
*/
80
69
public convenience init ( resolver: @escaping ( @escaping ( ) -> ( ) ) -> ( ) ) {
81
- let closure = JSClosure { arguments -> ( ) in
70
+ let closure = JSOneshotClosure { arguments in
82
71
// The arguments are always coming from the `Promise` constructor, so we should be
83
72
// safe to assume their type here
84
73
resolver { arguments [ 0 ] . function!( ) }
74
+ return . undefined
85
75
}
86
76
self . init ( unsafe: JSObject . global. Promise. function!. new ( closure) )
87
- callbacks. append ( closure)
88
77
}
89
78
}
90
79
@@ -93,7 +82,7 @@ extension JSPromise where Failure: ConvertibleToJSValue {
93
82
two closure that your code should call to either resolve or reject this `JSPromise` instance.
94
83
*/
95
84
public convenience init ( resolver: @escaping ( @escaping ( Result < Success , JSError > ) -> ( ) ) -> ( ) ) {
96
- let closure = JSClosure { arguments -> ( ) in
85
+ let closure = JSOneshotClosure { arguments in
97
86
// The arguments are always coming from the `Promise` constructor, so we should be
98
87
// safe to assume their type here
99
88
let resolve = arguments [ 0 ] . function!
@@ -107,9 +96,9 @@ extension JSPromise where Failure: ConvertibleToJSValue {
107
96
reject ( error. jsValue ( ) )
108
97
}
109
98
}
99
+ return . undefined
110
100
}
111
101
self . init ( unsafe: JSObject . global. Promise. function!. new ( closure) )
112
- callbacks. append ( closure)
113
102
}
114
103
}
115
104
@@ -118,7 +107,7 @@ extension JSPromise where Success: ConvertibleToJSValue, Failure: JSError {
118
107
a closure that your code should call to either resolve or reject this `JSPromise` instance.
119
108
*/
120
109
public convenience init ( resolver: @escaping ( @escaping ( Result < Success , JSError > ) -> ( ) ) -> ( ) ) {
121
- let closure = JSClosure { arguments -> ( ) in
110
+ let closure = JSOneshotClosure { arguments in
122
111
// The arguments are always coming from the `Promise` constructor, so we should be
123
112
// safe to assume their type here
124
113
let resolve = arguments [ 0 ] . function!
@@ -132,9 +121,9 @@ extension JSPromise where Success: ConvertibleToJSValue, Failure: JSError {
132
121
reject ( error. jsValue ( ) )
133
122
}
134
123
}
124
+ return . undefined
135
125
}
136
126
self . init ( unsafe: JSObject . global. Promise. function!. new ( closure) )
137
- callbacks. append ( closure)
138
127
}
139
128
}
140
129
@@ -146,13 +135,13 @@ extension JSPromise where Success: ConstructibleFromJSValue {
146
135
file: StaticString = #file,
147
136
line: Int = #line
148
137
) {
149
- let closure = JSClosure { arguments -> ( ) in
138
+ let closure = JSOneshotClosure { arguments in
150
139
guard let result = Success . construct ( from: arguments [ 0 ] ) else {
151
140
fatalError ( " \( file) : \( line) : failed to unwrap success value for `then` callback " )
152
141
}
153
142
success ( result)
143
+ return . undefined
154
144
}
155
- callbacks. append ( closure)
156
145
_ = jsObject. then!( closure)
157
146
}
158
147
@@ -165,13 +154,12 @@ extension JSPromise where Success: ConstructibleFromJSValue {
165
154
file: StaticString = #file,
166
155
line: Int = #line
167
156
) -> JSPromise < ResultType , Failure > {
168
- let closure = JSClosure { arguments -> JSValue in
157
+ let closure = JSOneshotClosure { arguments -> JSValue in
169
158
guard let result = Success . construct ( from: arguments [ 0 ] ) else {
170
159
fatalError ( " \( file) : \( line) : failed to unwrap success value for `then` callback " )
171
160
}
172
161
return success ( result) . jsValue ( )
173
162
}
174
- callbacks. append ( closure)
175
163
return . init( unsafe: jsObject. then!( closure) . object!)
176
164
}
177
165
@@ -184,13 +172,12 @@ extension JSPromise where Success: ConstructibleFromJSValue {
184
172
file: StaticString = #file,
185
173
line: Int = #line
186
174
) -> JSPromise < ResultSuccess , ResultFailure > {
187
- let closure = JSClosure { arguments -> JSValue in
175
+ let closure = JSOneshotClosure { arguments -> JSValue in
188
176
guard let result = Success . construct ( from: arguments [ 0 ] ) else {
189
177
fatalError ( " \( file) : \( line) : failed to unwrap success value for `then` callback " )
190
178
}
191
179
return success ( result) . jsValue ( )
192
180
}
193
- callbacks. append ( closure)
194
181
return . init( unsafe: jsObject. then!( closure) . object!)
195
182
}
196
183
}
@@ -205,13 +192,12 @@ extension JSPromise where Failure: ConstructibleFromJSValue {
205
192
file: StaticString = #file,
206
193
line: Int = #line
207
194
) -> JSPromise < ResultSuccess , Never > {
208
- let closure = JSClosure { arguments -> JSValue in
195
+ let closure = JSOneshotClosure { arguments -> JSValue in
209
196
guard let error = Failure . construct ( from: arguments [ 0 ] ) else {
210
197
fatalError ( " \( file) : \( line) : failed to unwrap error value for `catch` callback " )
211
198
}
212
199
return failure ( error) . jsValue ( )
213
200
}
214
- callbacks. append ( closure)
215
201
return . init( unsafe: jsObject. then!( JSValue . undefined, closure) . object!)
216
202
}
217
203
@@ -222,13 +208,13 @@ extension JSPromise where Failure: ConstructibleFromJSValue {
222
208
file: StaticString = #file,
223
209
line: Int = #line
224
210
) {
225
- let closure = JSClosure { arguments -> ( ) in
211
+ let closure = JSOneshotClosure { arguments in
226
212
guard let error = Failure . construct ( from: arguments [ 0 ] ) else {
227
213
fatalError ( " \( file) : \( line) : failed to unwrap error value for `catch` callback " )
228
214
}
229
215
failure ( error)
216
+ return . undefined
230
217
}
231
- callbacks. append ( closure)
232
218
_ = jsObject. then!( JSValue . undefined, closure)
233
219
}
234
220
@@ -241,13 +227,12 @@ extension JSPromise where Failure: ConstructibleFromJSValue {
241
227
file: StaticString = #file,
242
228
line: Int = #line
243
229
) -> JSPromise < ResultSuccess , ResultFailure > {
244
- let closure = JSClosure { arguments -> JSValue in
230
+ let closure = JSOneshotClosure { arguments -> JSValue in
245
231
guard let error = Failure . construct ( from: arguments [ 0 ] ) else {
246
232
fatalError ( " \( file) : \( line) : failed to unwrap error value for `catch` callback " )
247
233
}
248
234
return failure ( error) . jsValue ( )
249
235
}
250
- callbacks. append ( closure)
251
236
return . init( unsafe: jsObject. then!( JSValue . undefined, closure) . object!)
252
237
}
253
238
}
0 commit comments