@@ -8,20 +8,11 @@ is of actual JavaScript `Error` type, you should use `JSPromise<JSValue, JSValue
88This doesn't 100% match the JavaScript API, as `then` overload with two callbacks is not available.
99It's impossible to unify success and failure types from both callbacks in a single returned promise
1010without 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`.
1811*/
1912public final class JSPromise < Success, Failure> : ConvertibleToJSValue , ConstructibleFromJSValue {
2013 /// The underlying JavaScript `Promise` object.
2114 public let jsObject : JSObject
2215
23- private var callbacks = [ JSClosure] ( )
24-
2516 /// The underlying JavaScript `Promise` object wrapped as `JSValue`.
2617 public func jsValue( ) -> JSValue {
2718 . object( jsObject)
@@ -52,44 +43,37 @@ public final class JSPromise<Success, Failure>: ConvertibleToJSValue, Constructi
5243 /** Schedules the `success` closure to be invoked on sucessful completion of `self`.
5344 */
5445 public func then( success: @escaping ( ) -> ( ) ) {
55- let closure = JSClosure { _ in
46+ let closure = JSOneshotClosure { _ in
5647 success ( )
5748 return . undefined
5849 }
59- callbacks. append ( closure)
6050 _ = jsObject. then!( closure)
6151 }
6252
6353 /** Schedules the `failure` closure to be invoked on either successful or rejected completion of
6454 `self`.
6555 */
6656 public func finally( successOrFailure: @escaping ( ) -> ( ) ) -> Self {
67- let closure = JSClosure { _ in
57+ let closure = JSOneshotClosure { _ in
6858 successOrFailure ( )
6959 return . undefined
7060 }
71- callbacks. append ( closure)
7261 return . init( unsafe: jsObject. finally!( closure) . object!)
7362 }
74-
75- deinit {
76- callbacks. forEach { $0. release ( ) }
77- }
7863}
7964
8065extension JSPromise where Success == ( ) , Failure == Never {
8166 /** Creates a new `JSPromise` instance from a given `resolver` closure. `resolver` takes
8267 a closure that your code should call to resolve this `JSPromise` instance.
8368 */
8469 public convenience init ( resolver: @escaping ( @escaping ( ) -> ( ) ) -> ( ) ) {
85- let closure = JSClosure { arguments in
70+ let closure = JSOneshotClosure { arguments in
8671 // The arguments are always coming from the `Promise` constructor, so we should be
8772 // safe to assume their type here
8873 resolver { arguments [ 0 ] . function!( ) }
8974 return . undefined
9075 }
9176 self . init ( unsafe: JSObject . global. Promise. function!. new ( closure) )
92- callbacks. append ( closure)
9377 }
9478}
9579
@@ -98,7 +82,7 @@ extension JSPromise where Failure: ConvertibleToJSValue {
9882 two closure that your code should call to either resolve or reject this `JSPromise` instance.
9983 */
10084 public convenience init ( resolver: @escaping ( @escaping ( Result < Success , JSError > ) -> ( ) ) -> ( ) ) {
101- let closure = JSClosure { arguments in
85+ let closure = JSOneshotClosure { arguments in
10286 // The arguments are always coming from the `Promise` constructor, so we should be
10387 // safe to assume their type here
10488 let resolve = arguments [ 0 ] . function!
@@ -115,7 +99,6 @@ extension JSPromise where Failure: ConvertibleToJSValue {
11599 return . undefined
116100 }
117101 self . init ( unsafe: JSObject . global. Promise. function!. new ( closure) )
118- callbacks. append ( closure)
119102 }
120103}
121104
@@ -124,7 +107,7 @@ extension JSPromise where Success: ConvertibleToJSValue, Failure: JSError {
124107 a closure that your code should call to either resolve or reject this `JSPromise` instance.
125108 */
126109 public convenience init ( resolver: @escaping ( @escaping ( Result < Success , JSError > ) -> ( ) ) -> ( ) ) {
127- let closure = JSClosure { arguments in
110+ let closure = JSOneshotClosure { arguments in
128111 // The arguments are always coming from the `Promise` constructor, so we should be
129112 // safe to assume their type here
130113 let resolve = arguments [ 0 ] . function!
@@ -141,7 +124,6 @@ extension JSPromise where Success: ConvertibleToJSValue, Failure: JSError {
141124 return . undefined
142125 }
143126 self . init ( unsafe: JSObject . global. Promise. function!. new ( closure) )
144- callbacks. append ( closure)
145127 }
146128}
147129
@@ -153,14 +135,13 @@ extension JSPromise where Success: ConstructibleFromJSValue {
153135 file: StaticString = #file,
154136 line: Int = #line
155137 ) {
156- let closure = JSClosure { arguments in
138+ let closure = JSOneshotClosure { arguments in
157139 guard let result = Success . construct ( from: arguments [ 0 ] ) else {
158140 fatalError ( " \( file) : \( line) : failed to unwrap success value for `then` callback " )
159141 }
160142 success ( result)
161143 return . undefined
162144 }
163- callbacks. append ( closure)
164145 _ = jsObject. then!( closure)
165146 }
166147
@@ -173,13 +154,12 @@ extension JSPromise where Success: ConstructibleFromJSValue {
173154 file: StaticString = #file,
174155 line: Int = #line
175156 ) -> JSPromise < ResultType , Failure > {
176- let closure = JSClosure { arguments -> JSValue in
157+ let closure = JSOneshotClosure { arguments -> JSValue in
177158 guard let result = Success . construct ( from: arguments [ 0 ] ) else {
178159 fatalError ( " \( file) : \( line) : failed to unwrap success value for `then` callback " )
179160 }
180161 return success ( result) . jsValue ( )
181162 }
182- callbacks. append ( closure)
183163 return . init( unsafe: jsObject. then!( closure) . object!)
184164 }
185165
@@ -192,13 +172,12 @@ extension JSPromise where Success: ConstructibleFromJSValue {
192172 file: StaticString = #file,
193173 line: Int = #line
194174 ) -> JSPromise < ResultSuccess , ResultFailure > {
195- let closure = JSClosure { arguments -> JSValue in
175+ let closure = JSOneshotClosure { arguments -> JSValue in
196176 guard let result = Success . construct ( from: arguments [ 0 ] ) else {
197177 fatalError ( " \( file) : \( line) : failed to unwrap success value for `then` callback " )
198178 }
199179 return success ( result) . jsValue ( )
200180 }
201- callbacks. append ( closure)
202181 return . init( unsafe: jsObject. then!( closure) . object!)
203182 }
204183}
@@ -213,13 +192,12 @@ extension JSPromise where Failure: ConstructibleFromJSValue {
213192 file: StaticString = #file,
214193 line: Int = #line
215194 ) -> JSPromise < ResultSuccess , Never > {
216- let closure = JSClosure { arguments -> JSValue in
195+ let closure = JSOneshotClosure { arguments -> JSValue in
217196 guard let error = Failure . construct ( from: arguments [ 0 ] ) else {
218197 fatalError ( " \( file) : \( line) : failed to unwrap error value for `catch` callback " )
219198 }
220199 return failure ( error) . jsValue ( )
221200 }
222- callbacks. append ( closure)
223201 return . init( unsafe: jsObject. then!( JSValue . undefined, closure) . object!)
224202 }
225203
@@ -230,14 +208,13 @@ extension JSPromise where Failure: ConstructibleFromJSValue {
230208 file: StaticString = #file,
231209 line: Int = #line
232210 ) {
233- let closure = JSClosure { arguments in
211+ let closure = JSOneshotClosure { arguments in
234212 guard let error = Failure . construct ( from: arguments [ 0 ] ) else {
235213 fatalError ( " \( file) : \( line) : failed to unwrap error value for `catch` callback " )
236214 }
237215 failure ( error)
238216 return . undefined
239217 }
240- callbacks. append ( closure)
241218 _ = jsObject. then!( JSValue . undefined, closure)
242219 }
243220
@@ -250,13 +227,12 @@ extension JSPromise where Failure: ConstructibleFromJSValue {
250227 file: StaticString = #file,
251228 line: Int = #line
252229 ) -> JSPromise < ResultSuccess , ResultFailure > {
253- let closure = JSClosure { arguments -> JSValue in
230+ let closure = JSOneshotClosure { arguments -> JSValue in
254231 guard let error = Failure . construct ( from: arguments [ 0 ] ) else {
255232 fatalError ( " \( file) : \( line) : failed to unwrap error value for `catch` callback " )
256233 }
257234 return failure ( error) . jsValue ( )
258235 }
259- callbacks. append ( closure)
260236 return . init( unsafe: jsObject. then!( JSValue . undefined, closure) . object!)
261237 }
262238}
0 commit comments