[webkit-changes] [WebKit/WebKit] a53ad4: Implement NativePromise
Jean-Yves Avenard
noreply at github.com
Tue Sep 19 06:24:34 PDT 2023
Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: a53ad484a1c9fd497ba71ddbad3d934edbdd1d9c
https://github.com/WebKit/WebKit/commit/a53ad484a1c9fd497ba71ddbad3d934edbdd1d9c
Author: Jean-Yves Avenard <jya at apple.com>
Date: 2023-09-19 (Tue, 19 Sep 2023)
Changed paths:
M Source/WTF/WTF.xcodeproj/project.pbxproj
M Source/WTF/wtf/CMakeLists.txt
M Source/WTF/wtf/Logging.cpp
M Source/WTF/wtf/Logging.h
A Source/WTF/wtf/NativePromise.cpp
A Source/WTF/wtf/NativePromise.h
A Source/WTF/wtf/TypeTraits.h
M Source/WebCore/platform/Logging.h
M Tools/TestWebKitAPI/CMakeLists.txt
M Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
A Tools/TestWebKitAPI/Tests/WTF/NativePromise.cpp
Log Message:
-----------
Implement NativePromise
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
More information about the webkit-changes
mailing list