@@ -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,44 +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
46
+ let closure = JSOneshotClosure { _ in
56
47
success ( )
57
48
return . undefined
58
49
}
59
- callbacks. append ( closure)
60
50
_ = jsObject. then!( closure)
61
51
}
62
52
63
53
/** Schedules the `failure` closure to be invoked on either successful or rejected completion of
64
54
`self`.
65
55
*/
66
56
public func finally( successOrFailure: @escaping ( ) -> ( ) ) -> Self {
67
- let closure = JSClosure { _ in
57
+ let closure = JSOneshotClosure { _ in
68
58
successOrFailure ( )
69
59
return . undefined
70
60
}
71
- callbacks. append ( closure)
72
61
return . init( unsafe: jsObject. finally!( closure) . object!)
73
62
}
74
-
75
- deinit {
76
- callbacks. forEach { $0. release ( ) }
77
- }
78
63
}
79
64
80
65
extension JSPromise where Success == ( ) , Failure == Never {
81
66
/** Creates a new `JSPromise` instance from a given `resolver` closure. `resolver` takes
82
67
a closure that your code should call to resolve this `JSPromise` instance.
83
68
*/
84
69
public convenience init ( resolver: @escaping ( @escaping ( ) -> ( ) ) -> ( ) ) {
85
- let closure = JSClosure { arguments in
70
+ let closure = JSOneshotClosure { arguments in
86
71
// The arguments are always coming from the `Promise` constructor, so we should be
87
72
// safe to assume their type here
88
73
resolver { arguments [ 0 ] . function!( ) }
89
74
return . undefined
90
75
}
91
76
self . init ( unsafe: JSObject . global. Promise. function!. new ( closure) )
92
- callbacks. append ( closure)
93
77
}
94
78
}
95
79
@@ -98,7 +82,7 @@ extension JSPromise where Failure: ConvertibleToJSValue {
98
82
two closure that your code should call to either resolve or reject this `JSPromise` instance.
99
83
*/
100
84
public convenience init ( resolver: @escaping ( @escaping ( Result < Success , JSError > ) -> ( ) ) -> ( ) ) {
101
- let closure = JSClosure { arguments in
85
+ let closure = JSOneshotClosure { arguments in
102
86
// The arguments are always coming from the `Promise` constructor, so we should be
103
87
// safe to assume their type here
104
88
let resolve = arguments [ 0 ] . function!
@@ -115,7 +99,6 @@ extension JSPromise where Failure: ConvertibleToJSValue {
115
99
return . undefined
116
100
}
117
101
self . init ( unsafe: JSObject . global. Promise. function!. new ( closure) )
118
- callbacks. append ( closure)
119
102
}
120
103
}
121
104
@@ -124,7 +107,7 @@ extension JSPromise where Success: ConvertibleToJSValue, Failure: JSError {
124
107
a closure that your code should call to either resolve or reject this `JSPromise` instance.
125
108
*/
126
109
public convenience init ( resolver: @escaping ( @escaping ( Result < Success , JSError > ) -> ( ) ) -> ( ) ) {
127
- let closure = JSClosure { arguments in
110
+ let closure = JSOneshotClosure { arguments in
128
111
// The arguments are always coming from the `Promise` constructor, so we should be
129
112
// safe to assume their type here
130
113
let resolve = arguments [ 0 ] . function!
@@ -141,7 +124,6 @@ extension JSPromise where Success: ConvertibleToJSValue, Failure: JSError {
141
124
return . undefined
142
125
}
143
126
self . init ( unsafe: JSObject . global. Promise. function!. new ( closure) )
144
- callbacks. append ( closure)
145
127
}
146
128
}
147
129
@@ -153,14 +135,13 @@ extension JSPromise where Success: ConstructibleFromJSValue {
153
135
file: StaticString = #file,
154
136
line: Int = #line
155
137
) {
156
- let closure = JSClosure { arguments in
138
+ let closure = JSOneshotClosure { arguments in
157
139
guard let result = Success . construct ( from: arguments [ 0 ] ) else {
158
140
fatalError ( " \( file) : \( line) : failed to unwrap success value for `then` callback " )
159
141
}
160
142
success ( result)
161
143
return . undefined
162
144
}
163
- callbacks. append ( closure)
164
145
_ = jsObject. then!( closure)
165
146
}
166
147
@@ -173,13 +154,12 @@ extension JSPromise where Success: ConstructibleFromJSValue {
173
154
file: StaticString = #file,
174
155
line: Int = #line
175
156
) -> JSPromise < ResultType , Failure > {
176
- let closure = JSClosure { arguments -> JSValue in
157
+ let closure = JSOneshotClosure { arguments -> JSValue in
177
158
guard let result = Success . construct ( from: arguments [ 0 ] ) else {
178
159
fatalError ( " \( file) : \( line) : failed to unwrap success value for `then` callback " )
179
160
}
180
161
return success ( result) . jsValue ( )
181
162
}
182
- callbacks. append ( closure)
183
163
return . init( unsafe: jsObject. then!( closure) . object!)
184
164
}
185
165
@@ -192,13 +172,12 @@ extension JSPromise where Success: ConstructibleFromJSValue {
192
172
file: StaticString = #file,
193
173
line: Int = #line
194
174
) -> JSPromise < ResultSuccess , ResultFailure > {
195
- let closure = JSClosure { arguments -> JSValue in
175
+ let closure = JSOneshotClosure { arguments -> JSValue in
196
176
guard let result = Success . construct ( from: arguments [ 0 ] ) else {
197
177
fatalError ( " \( file) : \( line) : failed to unwrap success value for `then` callback " )
198
178
}
199
179
return success ( result) . jsValue ( )
200
180
}
201
- callbacks. append ( closure)
202
181
return . init( unsafe: jsObject. then!( closure) . object!)
203
182
}
204
183
}
@@ -213,13 +192,12 @@ extension JSPromise where Failure: ConstructibleFromJSValue {
213
192
file: StaticString = #file,
214
193
line: Int = #line
215
194
) -> JSPromise < ResultSuccess , Never > {
216
- let closure = JSClosure { arguments -> JSValue in
195
+ let closure = JSOneshotClosure { arguments -> JSValue in
217
196
guard let error = Failure . construct ( from: arguments [ 0 ] ) else {
218
197
fatalError ( " \( file) : \( line) : failed to unwrap error value for `catch` callback " )
219
198
}
220
199
return failure ( error) . jsValue ( )
221
200
}
222
- callbacks. append ( closure)
223
201
return . init( unsafe: jsObject. then!( JSValue . undefined, closure) . object!)
224
202
}
225
203
@@ -230,14 +208,13 @@ extension JSPromise where Failure: ConstructibleFromJSValue {
230
208
file: StaticString = #file,
231
209
line: Int = #line
232
210
) {
233
- let closure = JSClosure { arguments in
211
+ let closure = JSOneshotClosure { arguments in
234
212
guard let error = Failure . construct ( from: arguments [ 0 ] ) else {
235
213
fatalError ( " \( file) : \( line) : failed to unwrap error value for `catch` callback " )
236
214
}
237
215
failure ( error)
238
216
return . undefined
239
217
}
240
- callbacks. append ( closure)
241
218
_ = jsObject. then!( JSValue . undefined, closure)
242
219
}
243
220
@@ -250,13 +227,12 @@ extension JSPromise where Failure: ConstructibleFromJSValue {
250
227
file: StaticString = #file,
251
228
line: Int = #line
252
229
) -> JSPromise < ResultSuccess , ResultFailure > {
253
- let closure = JSClosure { arguments -> JSValue in
230
+ let closure = JSOneshotClosure { arguments -> JSValue in
254
231
guard let error = Failure . construct ( from: arguments [ 0 ] ) else {
255
232
fatalError ( " \( file) : \( line) : failed to unwrap error value for `catch` callback " )
256
233
}
257
234
return failure ( error) . jsValue ( )
258
235
}
259
- callbacks. append ( closure)
260
236
return . init( unsafe: jsObject. then!( JSValue . undefined, closure) . object!)
261
237
}
262
238
}
0 commit comments