diff --git a/index.bs b/index.bs index a55b526..580e432 100644 --- a/index.bs +++ b/index.bs @@ -1877,6 +1877,62 @@ If the bytes in the buffer have a natural intepretation as one of the other TypedArray types, provide that instead. For example, if the bytes represent Float32 values, use a {{Float32Array}}. +

A Promise represents completion or a value, not a callback

+ +Avoid requiring that something needs to happen synchronously within +a promise resolution or rejection callback. + +This breaks basic assumptions around asynchronous APIs being wrappable. +Authors tend to expect that any `async` function can be wrapped +in another that appends synchronous code at the end. +This might be to examine a resolved value or rejection using try/catch. +But using `await` or similar wrappers queue a microtask: +
+```js +async function fooWrapper() { + const foo = await platform.foo(); + console.log("success"); + return foo; +} + +(async () => { + const foo = await fooWrapper(); + foo.bar(); // on the same task, but not the same microtask that logged "success" +})(); +``` +
+ +In general, the settled result from an asynchronous function +should be usable at any time. + +However, if the result of your API is timing sensitive, you might need +to restrict when it can be acted on. + +In the above example, perhaps the `platform.foo()` function +establishes state that has real-time dependencies such that calling +`bar()` is not viable at any future time. + +Never limit the viability of acting on a settled result to a microtask, +as this prevents most forms of code composition. + +If possible, set a short timeout interval. Failing that, viability can +be limited to the same task, but not a single microtask. + +
+One case where this came up was the [captureController.setFocusBehavior()](https://w3c.github.io/mediacapture-screen-share/#dom-capturecontroller-setfocusbehavior) +method which controls whether a window the user selects to screen-capture +should immediately be pushed to the front or not. It can be called as late +as right after the resolution of the `getDisplayMedia()` promise. This allows +applications to make a different decision based on the window the user chose. +But the application must act right away or this becomes surprising to the user. + +The solution was to add a timeout on top of the requirement of it being +called on the same task that resolves the `getDisplayMedia()` promise. +
+ +If an API depends on setting up temporary conditions then invoking the caller, +that is a good reason to use a callback rather than a promise. +

Event Design

Use promises for one time events