Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
https://bugs.webkit.org/show_bug.cgi?id=254502 rdar://107546076 Reviewed by Youenn Fablet. This is a WTF C++ native JS's like Promise, inspired by Gecko's MozPromise object There are some significant differences from the gecko's implemtation, both from a modus of operations and syntax usage in order to better fit with WebKit, in particular: - NativePromise can have a resolveType of `void` - NativePromise takes a SerialFunctionDispatcher with ref/deref methods and is a template argument. - There's typically no need to specify the return types of the resolve/reject callbacks. `auto` should work in most cases. About NativePromise: A promise manages an asynchronous request that may or may not be able to be fulfilled immediately. When an API returns a promise, the consumer may attach callbacks to be invoked (asynchronously, on a specified thread) when the request is either completed (resolved) or cannot be completed (rejected). A NativePromise object is thread safe, and may be ->then()ed on any thread. The then() call accepts either a resolve and reject callback, while whenSettled() accepts a resolveOrReject one. NativePromise::then() and NativePromise::whenSettled() returns a NativePromise::Request object. This request can be either: 1- Converted back to a NativePromise which will be resolved or rejected once the resolve/reject callbacks are run. This new NativePromise can be then()ed again to chain multiple operations. 2- Be tracked using a NativePromiseRequest: this allows the caller to cancel the delivery of the resolve/reject result if it has not already occurred. (call to NativePromiseRequest::disconnect() must be done on the target thread to avoid thread safety issues). When IsExclusive is true: - The NativePromise performs run-time assertions that there is at most one call to either then(...) or chainTo(...). - Move semantics are used when passing arguments - The resolved or rejected object will be deleted on the target thread. - The ResolveValueType and RejectValueType must have a move constructor if IsExclusive is true. Compilation will fail otherwise. Otherwise: - values are passed to the resolve/reject callbacks through either const references or pointers. - the resolve or reject object will be deleted on the last SerialFunctionDispatcher that got used. A typical workflow would be as follow: If the work is to be done immediately: From the producer side: - Do the work - return a resolved or rejected promise via NativePromise::createAndResolve or NativePromise::createAndReject From the consumer side: - call the method returning a promise - then()/whenSettled() on the promise to set the actions to run once the promise has settled. If the work is to be done at a later stage: From the producer side: - Allocate a NativePromise::Producer (via NativePromise::Producer::create() and return it to the consumer has a Ref<NativePromise> - Do the work - Once the work has been completed, either resolve or reject the NativePromise::Producer object. From the consumer side: - call the method returning a promise - then() on the promise to set the actions to run once the promise has settled. In either case (immediate or later resolution) using a NativePromiseRequest: - track the promise - cancel the delivery of the resolve/reject result and prevent callbacks to be run. By disconnecting the NativePromiseRequest (via NativePromiseRequest::disconnect(), the then() callbacks will not be run. Example: ``` // You can mix & match promise types and chain them together. using MyPromise = NativePromise<int, int, true>; GenericPromise::Producer p(__func__); using MyPromise = NativePromise<int, int, true>; p->whenSettled(queue, __func__, [] (GenericPromise::Result result) { return MyPromise::createAndResolve(1, __func__); })->whenSettled(queue, __func__, [queue] (MyPromise::Result result) { static_assert(std::is_same_v<MyPromise::Result::value_type, int>, "The type received is the same as the last promise returned"); EXPECT_TRUE(result.has_value()); EXPECT_EQ(result.value(), 1); queue->beginShutdown(); }); p.resolve(__func__); ``` API tests added (re-used from Gecko's source code and adapted for NativePromise) Canonical link: https://commits.webkit.org/268120@main
- Loading branch information