1
1
#import " KrollPromise.h"
2
+ #import " KrollObject.h"
2
3
#import " TiExceptionHandler.h"
3
4
4
5
@implementation KrollPromise
5
6
6
7
- (KrollPromise *)initInContext : (JSContext *)context
7
8
{
8
9
if (self = [super init ]) {
10
+ if ([KrollObject isFinalizing ]) {
11
+ // We cannot create a Promise in this context! If an object is being finalized the function
12
+ // we call to generate a Promise will crash complaining about the Promise constructor not being an object!
13
+ return self;
14
+ }
9
15
if (@available (iOS 13 , *)) {
10
16
// Use iOS 13 APIs.
11
17
JSObjectRef resolve;
12
18
JSObjectRef reject;
13
19
JSValueRef exception = NULL ;
14
-
15
20
JSObjectRef promiseRef = JSObjectMakeDeferredPromise (context.JSGlobalContextRef , &resolve, &reject, &exception );
16
21
if (exception ) {
17
- // FIXME: Randomly getting "null is not an object" and I don't know what is null here. The context? The Promise prototype?
18
22
// report exception
19
23
JSValue *error = [JSValue valueWithJSValueRef: exception inContext: context];
20
- NSLog (@" %@ " , error[@" message" ]);
21
24
[context setException: error];
22
25
_JSValue = [[JSValue valueWithUndefinedInContext: context] retain ];
23
26
resolveFunc = [[JSValue valueWithUndefinedInContext: context] retain ];
@@ -41,7 +44,6 @@ - (KrollPromise *)initInContext:(JSContext *)context
41
44
if (exception != nil ) {
42
45
[TiExceptionHandler.defaultExceptionHandler reportScriptError: exception inJSContext: context];
43
46
}
44
- // FIXME: Do we need to use a ManagedJSValue here rather than retain it? We do expose it to the JS Engine!
45
47
_JSValue = [[createPromise callWithArguments: @[ executor ]] retain ];
46
48
resolveFunc = [executor[@" resolve" ] retain ];
47
49
rejectFunc = [executor[@" reject" ] retain ];
@@ -67,35 +69,75 @@ + (KrollPromise *)rejected:(NSArray *)arguments inContext:(JSContext *)context
67
69
+ (KrollPromise *)rejectedWithErrorMessage : (NSString *)message inContext : (JSContext *)context
68
70
{
69
71
KrollPromise *promise = [[[KrollPromise alloc ] initInContext: context] autorelease ];
70
- JSValue *error = [JSValue valueWithNewErrorFromMessage: message inContext: context];
71
- [promise reject: @[ error ]];
72
+ [promise rejectWithErrorMessage: message];
72
73
return promise;
73
74
}
74
75
75
76
- (void )resolve : (NSArray *)arguments
76
77
{
77
- [resolveFunc callWithArguments: arguments];
78
+ if (resolveFunc) {
79
+ [resolveFunc callWithArguments: arguments];
80
+ }
81
+ _fulfilled = YES ;
82
+ if (_flushMe) {
83
+ [self flush ];
84
+ _flushMe = NO ;
85
+ }
78
86
}
79
87
80
88
- (void )reject : (NSArray *)arguments
81
89
{
82
- [rejectFunc callWithArguments: arguments];
90
+ if (rejectFunc) {
91
+ [rejectFunc callWithArguments: arguments];
92
+ }
93
+ _fulfilled = YES ;
94
+ if (_flushMe) {
95
+ [self flush ];
96
+ _flushMe = NO ;
97
+ }
98
+ }
99
+
100
+ // We need to handle "settling" fulfillments/rejections so we don't leave unhandled rejections around
101
+ - (void )flush
102
+ {
103
+ if (_JSValue == nil ) {
104
+ // assume no-op Promise generated during finalization
105
+ return ;
106
+ }
107
+ if (_fulfilled) {
108
+ JSValue *noop = [JSValue
109
+ valueWithObject: ^() {
110
+ }
111
+ inContext: rejectFunc.context];
112
+ [_JSValue invokeMethod: @" then" withArguments: @[ noop, noop ]];
113
+ } else {
114
+ // not yet fulfilled/rejected, so mark it to get flushed after it is
115
+ _flushMe = YES ;
116
+ }
83
117
}
84
118
85
119
- (void )rejectWithErrorMessage : (NSString *)message
86
120
{
87
- JSValue *error = [JSValue valueWithNewErrorFromMessage: message inContext: rejectFunc.context];
88
- [self reject: @[ error ]];
121
+ if (rejectFunc) {
122
+ JSValue *error = [JSValue valueWithNewErrorFromMessage: message inContext: rejectFunc.context];
123
+ [self reject: @[ error ]];
124
+ }
89
125
}
90
126
91
127
- (void )dealloc
92
128
{
93
- [_JSValue release ];
94
- _JSValue = nil ;
95
- [resolveFunc release ];
96
- resolveFunc = nil ;
97
- [rejectFunc release ];
98
- rejectFunc = nil ;
129
+ if (_JSValue) {
130
+ [_JSValue release ];
131
+ _JSValue = nil ;
132
+ }
133
+ if (resolveFunc) {
134
+ [resolveFunc release ];
135
+ resolveFunc = nil ;
136
+ }
137
+ if (rejectFunc) {
138
+ [rejectFunc release ];
139
+ rejectFunc = nil ;
140
+ }
99
141
[super dealloc ];
100
142
}
101
143
0 commit comments