1
- /** A wrapper around [the JavaScript `Promise` class](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)
2
- that exposes its functions in a type-safe and Swifty way. The `JSPromise` API is generic over both
3
- `Success` and `Failure` types, which improves compatibility with other statically-typed APIs such
4
- as Combine. If you don't know the exact type of your `Success` value, you should use `JSValue`, e.g.
5
- `JSPromise<JSValue, JSError>`. In the rare case, where you can't guarantee that the error thrown
6
- is of actual JavaScript `Error` type, you should use `JSPromise<JSValue, JSValue>`.
7
-
8
- This doesn't 100% match the JavaScript API, as `then` overload with two callbacks is not available.
9
- It's impossible to unify success and failure types from both callbacks in a single returned promise
10
- without type erasure. You should chain `then` and `catch` in those cases to avoid type erasure.
11
- */
1
+ /// A wrapper around [the JavaScript `Promise` class](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)
12
2
public final class JSPromise : JSBridgedClass {
13
3
/// The underlying JavaScript `Promise` object.
14
4
public let jsObject : JSObject
@@ -27,25 +17,27 @@ public final class JSPromise: JSBridgedClass {
27
17
jsObject = object
28
18
}
29
19
30
- /** Creates a new `JSPromise` instance from a given JavaScript `Promise` object. If `jsObject`
31
- is not an instance of JavaScript `Promise`, this initializer will return `nil`.
32
- */
20
+ /// Creates a new `JSPromise` instance from a given JavaScript `Promise` object. If `jsObject`
21
+ /// is not an instance of JavaScript `Promise`, this initializer will return `nil`.
33
22
public convenience init ? ( _ jsObject: JSObject ) {
34
23
self . init ( from: jsObject)
35
24
}
36
25
37
- /** Creates a new `JSPromise` instance from a given JavaScript `Promise` object. If `value`
38
- is not an object and is not an instance of JavaScript `Promise`, this function will
39
- return `nil`.
40
- */
26
+ /// Creates a new `JSPromise` instance from a given JavaScript `Promise` object. If `value`
27
+ /// is not an object and is not an instance of JavaScript `Promise`, this function will
28
+ /// return `nil`.
41
29
public static func construct( from value: JSValue ) -> Self ? {
42
30
guard case let . object( jsObject) = value else { return nil }
43
31
return Self ( jsObject)
44
32
}
45
33
46
- /** Creates a new `JSPromise` instance from a given `resolver` closure. `resolver` takes
47
- two closure that your code should call to either resolve or reject this `JSPromise` instance.
48
- */
34
+ /// Creates a new `JSPromise` instance from a given `resolver` closure.
35
+ /// The closure is passed a completion handler. Passing a successful
36
+ /// `Result` to the completion handler will cause the promise to resolve
37
+ /// with the corresponding value; passing a failure `Result` will cause the
38
+ /// promise to reject with the corresponding value.
39
+ /// Calling the completion handler more than once will have no effect
40
+ /// (per the JavaScript specification).
49
41
public convenience init ( resolver: @escaping ( @escaping ( Result < JSValue , JSValue > ) -> Void ) -> Void ) {
50
42
let closure = JSOneshotClosure { arguments in
51
43
// The arguments are always coming from the `Promise` constructor, so we should be
@@ -74,8 +66,7 @@ public final class JSPromise: JSBridgedClass {
74
66
self . init ( unsafelyWrapping: Self . constructor!. reject!( reason) . object!)
75
67
}
76
68
77
- /** Schedules the `success` closure to be invoked on sucessful completion of `self`.
78
- */
69
+ /// Schedules the `success` closure to be invoked on successful completion of `self`.
79
70
@discardableResult
80
71
public func then( success: @escaping ( JSValue ) -> ConvertibleToJSValue ) -> JSPromise {
81
72
let closure = JSOneshotClosure {
@@ -84,8 +75,19 @@ public final class JSPromise: JSBridgedClass {
84
75
return JSPromise ( unsafelyWrapping: jsObject. then!( closure) . object!)
85
76
}
86
77
87
- /** Schedules the `success` closure to be invoked on sucessful completion of `self`.
88
- */
78
+ #if compiler(>=5.5)
79
+ /// Schedules the `success` closure to be invoked on successful completion of `self`.
80
+ @available ( macOS 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * )
81
+ @discardableResult
82
+ public func then( success: @escaping ( JSValue ) async throws -> ConvertibleToJSValue ) -> JSPromise {
83
+ let closure = JSOneshotClosure . async {
84
+ try await success ( $0 [ 0 ] ) . jsValue
85
+ }
86
+ return JSPromise ( unsafelyWrapping: jsObject. then!( closure) . object!)
87
+ }
88
+ #endif
89
+
90
+ /// Schedules the `success` closure to be invoked on successful completion of `self`.
89
91
@discardableResult
90
92
public func then(
91
93
success: @escaping ( JSValue ) -> ConvertibleToJSValue ,
@@ -100,8 +102,24 @@ public final class JSPromise: JSBridgedClass {
100
102
return JSPromise ( unsafelyWrapping: jsObject. then!( successClosure, failureClosure) . object!)
101
103
}
102
104
103
- /** Schedules the `failure` closure to be invoked on rejected completion of `self`.
104
- */
105
+ #if compiler(>=5.5)
106
+ /// Schedules the `success` closure to be invoked on successful completion of `self`.
107
+ @available ( macOS 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * )
108
+ @discardableResult
109
+ public func then( success: @escaping ( JSValue ) async throws -> ConvertibleToJSValue ,
110
+ failure: @escaping ( JSValue ) async throws -> ConvertibleToJSValue ) -> JSPromise
111
+ {
112
+ let successClosure = JSOneshotClosure . async {
113
+ try await success ( $0 [ 0 ] ) . jsValue
114
+ }
115
+ let failureClosure = JSOneshotClosure . async {
116
+ try await failure ( $0 [ 0 ] ) . jsValue
117
+ }
118
+ return JSPromise ( unsafelyWrapping: jsObject. then!( successClosure, failureClosure) . object!)
119
+ }
120
+ #endif
121
+
122
+ /// Schedules the `failure` closure to be invoked on rejected completion of `self`.
105
123
@discardableResult
106
124
public func `catch`( failure: @escaping ( JSValue ) -> ConvertibleToJSValue ) -> JSPromise {
107
125
let closure = JSOneshotClosure {
@@ -110,9 +128,20 @@ public final class JSPromise: JSBridgedClass {
110
128
return . init( unsafelyWrapping: jsObject. catch!( closure) . object!)
111
129
}
112
130
113
- /** Schedules the `failure` closure to be invoked on either successful or rejected completion of
114
- `self`.
115
- */
131
+ #if compiler(>=5.5)
132
+ /// Schedules the `failure` closure to be invoked on rejected completion of `self`.
133
+ @available ( macOS 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * )
134
+ @discardableResult
135
+ public func `catch`( failure: @escaping ( JSValue ) async throws -> ConvertibleToJSValue ) -> JSPromise {
136
+ let closure = JSOneshotClosure . async {
137
+ try await failure ( $0 [ 0 ] ) . jsValue
138
+ }
139
+ return . init( unsafelyWrapping: jsObject. catch!( closure) . object!)
140
+ }
141
+ #endif
142
+
143
+ /// Schedules the `failure` closure to be invoked on either successful or rejected
144
+ /// completion of `self`.
116
145
@discardableResult
117
146
public func finally( successOrFailure: @escaping ( ) -> Void ) -> JSPromise {
118
147
let closure = JSOneshotClosure { _ in
0 commit comments