@@ -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,39 +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 success ( ) }
56- callbacks. append ( closure)
46+ let closure = JSOneshotClosure { _ in
47+ success ( )
48+ return . undefined
49+ }
5750 _ = jsObject. then!( closure)
5851 }
5952
6053 /** Schedules the `failure` closure to be invoked on either successful or rejected completion of
6154 `self`.
6255 */
6356 public func finally( successOrFailure: @escaping ( ) -> ( ) ) -> Self {
64- let closure = JSClosure { _ in
57+ let closure = JSOneshotClosure { _ in
6558 successOrFailure ( )
59+ return . undefined
6660 }
67- callbacks. append ( closure)
6861 return . init( unsafe: jsObject. finally!( closure) . object!)
6962 }
70-
71- deinit {
72- callbacks. forEach { $0. release ( ) }
73- }
7463}
7564
7665extension JSPromise where Success == ( ) , Failure == Never {
7766 /** Creates a new `JSPromise` instance from a given `resolver` closure. `resolver` takes
7867 a closure that your code should call to resolve this `JSPromise` instance.
7968 */
8069 public convenience init ( resolver: @escaping ( @escaping ( ) -> ( ) ) -> ( ) ) {
81- let closure = JSClosure { arguments -> ( ) in
70+ let closure = JSOneshotClosure { arguments in
8271 // The arguments are always coming from the `Promise` constructor, so we should be
8372 // safe to assume their type here
8473 resolver { arguments [ 0 ] . function!( ) }
74+ return . undefined
8575 }
8676 self . init ( unsafe: JSObject . global. Promise. function!. new ( closure) )
87- callbacks. append ( closure)
8877 }
8978}
9079
@@ -93,7 +82,7 @@ extension JSPromise where Failure: ConvertibleToJSValue {
9382 two closure that your code should call to either resolve or reject this `JSPromise` instance.
9483 */
9584 public convenience init ( resolver: @escaping ( @escaping ( Result < Success , JSError > ) -> ( ) ) -> ( ) ) {
96- let closure = JSClosure { arguments -> ( ) in
85+ let closure = JSOneshotClosure { arguments in
9786 // The arguments are always coming from the `Promise` constructor, so we should be
9887 // safe to assume their type here
9988 let resolve = arguments [ 0 ] . function!
@@ -107,9 +96,9 @@ extension JSPromise where Failure: ConvertibleToJSValue {
10796 reject ( error. jsValue ( ) )
10897 }
10998 }
99+ return . undefined
110100 }
111101 self . init ( unsafe: JSObject . global. Promise. function!. new ( closure) )
112- callbacks. append ( closure)
113102 }
114103}
115104
@@ -118,7 +107,7 @@ extension JSPromise where Success: ConvertibleToJSValue, Failure: JSError {
118107 a closure that your code should call to either resolve or reject this `JSPromise` instance.
119108 */
120109 public convenience init ( resolver: @escaping ( @escaping ( Result < Success , JSError > ) -> ( ) ) -> ( ) ) {
121- let closure = JSClosure { arguments -> ( ) in
110+ let closure = JSOneshotClosure { arguments in
122111 // The arguments are always coming from the `Promise` constructor, so we should be
123112 // safe to assume their type here
124113 let resolve = arguments [ 0 ] . function!
@@ -132,9 +121,9 @@ extension JSPromise where Success: ConvertibleToJSValue, Failure: JSError {
132121 reject ( error. jsValue ( ) )
133122 }
134123 }
124+ return . undefined
135125 }
136126 self . init ( unsafe: JSObject . global. Promise. function!. new ( closure) )
137- callbacks. append ( closure)
138127 }
139128}
140129
@@ -146,13 +135,13 @@ extension JSPromise where Success: ConstructibleFromJSValue {
146135 file: StaticString = #file,
147136 line: Int = #line
148137 ) {
149- let closure = JSClosure { arguments -> ( ) in
138+ let closure = JSOneshotClosure { arguments in
150139 guard let result = Success . construct ( from: arguments [ 0 ] ) else {
151140 fatalError ( " \( file) : \( line) : failed to unwrap success value for `then` callback " )
152141 }
153142 success ( result)
143+ return . undefined
154144 }
155- callbacks. append ( closure)
156145 _ = jsObject. then!( closure)
157146 }
158147
@@ -165,13 +154,12 @@ extension JSPromise where Success: ConstructibleFromJSValue {
165154 file: StaticString = #file,
166155 line: Int = #line
167156 ) -> JSPromise < ResultType , Failure > {
168- let closure = JSClosure { arguments -> JSValue in
157+ let closure = JSOneshotClosure { arguments -> JSValue in
169158 guard let result = Success . construct ( from: arguments [ 0 ] ) else {
170159 fatalError ( " \( file) : \( line) : failed to unwrap success value for `then` callback " )
171160 }
172161 return success ( result) . jsValue ( )
173162 }
174- callbacks. append ( closure)
175163 return . init( unsafe: jsObject. then!( closure) . object!)
176164 }
177165
@@ -184,13 +172,12 @@ extension JSPromise where Success: ConstructibleFromJSValue {
184172 file: StaticString = #file,
185173 line: Int = #line
186174 ) -> JSPromise < ResultSuccess , ResultFailure > {
187- let closure = JSClosure { arguments -> JSValue in
175+ let closure = JSOneshotClosure { arguments -> JSValue in
188176 guard let result = Success . construct ( from: arguments [ 0 ] ) else {
189177 fatalError ( " \( file) : \( line) : failed to unwrap success value for `then` callback " )
190178 }
191179 return success ( result) . jsValue ( )
192180 }
193- callbacks. append ( closure)
194181 return . init( unsafe: jsObject. then!( closure) . object!)
195182 }
196183}
@@ -205,13 +192,12 @@ extension JSPromise where Failure: ConstructibleFromJSValue {
205192 file: StaticString = #file,
206193 line: Int = #line
207194 ) -> JSPromise < ResultSuccess , Never > {
208- let closure = JSClosure { arguments -> JSValue in
195+ let closure = JSOneshotClosure { arguments -> JSValue in
209196 guard let error = Failure . construct ( from: arguments [ 0 ] ) else {
210197 fatalError ( " \( file) : \( line) : failed to unwrap error value for `catch` callback " )
211198 }
212199 return failure ( error) . jsValue ( )
213200 }
214- callbacks. append ( closure)
215201 return . init( unsafe: jsObject. then!( JSValue . undefined, closure) . object!)
216202 }
217203
@@ -222,13 +208,13 @@ extension JSPromise where Failure: ConstructibleFromJSValue {
222208 file: StaticString = #file,
223209 line: Int = #line
224210 ) {
225- let closure = JSClosure { arguments -> ( ) in
211+ let closure = JSOneshotClosure { arguments in
226212 guard let error = Failure . construct ( from: arguments [ 0 ] ) else {
227213 fatalError ( " \( file) : \( line) : failed to unwrap error value for `catch` callback " )
228214 }
229215 failure ( error)
216+ return . undefined
230217 }
231- callbacks. append ( closure)
232218 _ = jsObject. then!( JSValue . undefined, closure)
233219 }
234220
@@ -241,13 +227,12 @@ extension JSPromise where Failure: ConstructibleFromJSValue {
241227 file: StaticString = #file,
242228 line: Int = #line
243229 ) -> JSPromise < ResultSuccess , ResultFailure > {
244- let closure = JSClosure { arguments -> JSValue in
230+ let closure = JSOneshotClosure { arguments -> JSValue in
245231 guard let error = Failure . construct ( from: arguments [ 0 ] ) else {
246232 fatalError ( " \( file) : \( line) : failed to unwrap error value for `catch` callback " )
247233 }
248234 return failure ( error) . jsValue ( )
249235 }
250- callbacks. append ( closure)
251236 return . init( unsafe: jsObject. then!( JSValue . undefined, closure) . object!)
252237 }
253238}
0 commit comments