| 279 | } |
| 280 | |
| 281 | Value ValueFunctionWithJSValue::callPromise(const Ref<JavaScriptTaskScheduler>& taskScheduler, |
| 282 | const ValueFunctionCallContext& callContext) { |
| 283 | auto promise = makeShared<ResolvablePromise>(); |
| 284 | |
| 285 | taskScheduler->dispatchOnJsThreadAsync( |
| 286 | getContext(), |
| 287 | [self = strongSmallRef(this), promise, parameters = captureParameters(callContext)](auto& jsEntry) { |
| 288 | Value result = self->doJsCall(jsEntry, parameters.data(), parameters.size(), nullptr, false); |
| 289 | if (!jsEntry.exceptionTracker) { |
| 290 | promise->fulfill(jsEntry.exceptionTracker.extractError()); |
| 291 | return; |
| 292 | } |
| 293 | |
| 294 | // When an interruptible callback is skipped (Valdi context destroyed), doJsCall returns |
| 295 | // undefined. Fulfilling the promise with undefined would cause native unmarshalling to |
| 296 | // fail (e.g. expected NativeSnapDoc). Reject the promise so the caller can handle it. |
| 297 | if (result.getType() == ValueType::Undefined && self->_ignoreIfValdiContextIsDestroyed && |
| 298 | self->getContext() != nullptr && self->getContext()->isDestroyed()) { |
| 299 | promise->fulfill(Result<Value>(Error("Valdi context destroyed"))); |
| 300 | return; |
| 301 | } |
| 302 | |
| 303 | auto nestedPromise = result.getTypedRef<Promise>(); |
| 304 | if (nestedPromise != nullptr) { |
| 305 | // Flatten one level of promise, since we already returned a promise to the caller |
| 306 | promise->fulfillWithPromiseResult(nestedPromise); |
| 307 | } else { |
| 308 | promise->fulfill(result); |
| 309 | } |
| 310 | }); |
| 311 | |
| 312 | return Value(promise); |
| 313 | } |
| 314 | |
| 315 | std::string_view ValueFunctionWithJSValue::getFunctionType() const { |
| 316 | return "JSFunction"; |
nothing calls this directly
no test coverage detected