Previous slide Next slide Toggle fullscreen Open presenter view
Promise.try: Deep Dive into Implementation and the Evolution of Promises
saku / @sakupi01
Promise.try: Deep Dive into Implementation and the Evolution of Promises
Available in JA
1. The Difficulty of Unifying Synchronous and Asynchronous Processing in JavaScript
e.g. A function called syncOrAsync
that can yield either synchronous or asynchronous results
function syncOrAsync (id ) {
if (typeof id !== "number" ) {
throw new Error ("id must be a number" );
}
return db.getUserById (id);
}
Method ①: Attempt to handle sync/async functions as they are
syncOrAsync ()
.then (console .log )
.catch (console .error );
Execution error, compile error in TypeScript
If it's a synchronous function, the then property does not exist
Method ②: Use Promise.resolve() as is
try {
Promise .resolve (syncOrAsync ())
.then (console .log )
.catch (console .error );
} catch (error) {
console .error (error);
}
If a synchronous error occurs, it cannot be caught with catch
Need to use try-catch to catch it
Method ③: Handle sync/async functions within Promise.resolve().then()
Promise .resolve ().then (syncOrAsync)
.then (console .log )
.catch (console .error );
Simple writing style
Even synchronous functions are executed asynchronously → unnecessarily asynchronous
Method ④: Create a new Promise and resolve sync/async functions within it
new Promise ((resolve ) => resolve (syncOrAsync ()))
.then (console .log )
.catch (console .error );
Unnecessary asynchronous processing does not occur
Writing style is verbose
Before Promise.try was standardized, libraries offering similar functionality existed
Adopted the method of "creating a new Promise and resolving sync/async functions within it" as in method ④
2. What Promise.try
Solves
Allows unified handling of synchronous and asynchronous processing without unnecessary asynchronous processing
Whether synchronous or asynchronous processing:
Can handle data in the same way
Can catch errors in the same way
Intuitive and simple syntax
Promise .try (syncOrAsync ())
.then (console .log )
.catch (console .error );
Convenient!
3. Dive into Promise.try in JSC
Let's Look at the Specification of Promise.try
NewPromiseCapability
Abstract Operation that generates a PromiseCapabilityRecord.
Ultimately returns a Normal Completion containing a PromiseCapabilityRecord
, or throws a Completion .
In JSC, it corresponds to @newPromiseCapability
27.2.1.5 NewPromiseCapability ( C )
Abstract Operations
A collection of operations commonly used within the ECMAScript specification
Conceptual functions within the specification that are called from other parts of the specification
5.2.1 Abstract Operations
Re: NewPromiseCapability
Abstract Operation that generates a PromiseCapabilityRecord.
Ultimately returns a Normal Completion containing a PromiseCapabilityRecord
, or throws a Completion .
In JSC, it corresponds to @newPromiseCapability
27.2.1.5 NewPromiseCapability ( C )
Completion Records; ?
and !
Returned to the runtime semantics of ECMAScript
If the type is Normal: Normal Completion.
!
(exclamation mark) : Used to indicate that the operation will never fail
If the type is not Normal: Abrupt Completion.
?
(question mark) : Used to indicate that the operation may fail
JSCでのPromise.tryの実装
function try (callback )
{
"use strict" ;
if (!@isObject (this ))
@throwTypeError ("|this| is not an object" );
var args = [];
for (var i = 1 ; i < arguments .length ; i++)
@putByValDirect (args, i - 1 , arguments [i]);
var promiseCapability = @newPromiseCapability (this );
...
[JSC] Implement Promise.try #24802
JSCでのPromise.tryの実装
...
try {
var value = callback.@apply (@undefined , args);
promiseCapability.resolve .@call (@undefined , value);
} catch (error) {
promiseCapability.reject .@call (@undefined , error);
}
return promiseCapability.promise ;
}
8 Years of Journey to Stage4
Why it took so long to reach Stage 4
Why it took so long to reach Stage 4
Promise.try took time to discuss whether "this feature is worth adding to the language specification"
Why it took so long to reach Stage 4
Progress of async/await
discussions
Discussions on async/await
to be included in ES2017 were progressing, and similar functionality seemed achievable with immediately-invoked async functions (AIIFE)
At that time, there was skepticism about whether adding new syntax was worth it
Difficulty in visualizing demand
In comprehensive libraries like Bluebird.js, it was difficult to isolate and measure the actual usage of the Promise.try feature
Packages like p-try did not yet exist
It was challenging to quantitatively demonstrate actual use cases and demand
Influence of Third-Party Libraries on Usage Progress
p-try
emerged, and it became apparent that it recorded a large number of downloads
Actual demand for Promise.try became visible
Standardization progressed rapidly
Recent Trends in ECMAScript Promises - Cancellation in Promise
A proposal to support Promise cancellation by adding a new state , canceled
, to the language specification
About 8 years ago...
Opposition from the V8 team to adding a new state
Without further details, this proposal became a public archive, and the Issue was closed
This proposal experienced significant opposition from within Google and so I am unable to continue working on it.
Why was this proposal withdrawn? #70
As of 2024: Promises Can Be Canceled (Sort of)
After the closure of cancelable-promises, AbortController was implemented in the DOM
By utilizing this, Promises can be canceled
AbortController is a DOM API
Challenges of AbortController
Dependent on the browser environment
Limited use in server-side JavaScript
There is an expectation to standardize the cancellation mechanism on the ECMAScript side to achieve unified cancellation processing
Challenges of Cancellation in Promise
Unless it is compatible with the already standardized AbortController, progress on the proposal is difficult
It becomes equivalent to generating a DOMException on the JS side, and discussions seem to be stalling
Summary
Promise.try()
reached Stage 4! Towards the unification of synchronous and asynchronous processing in JavaScript
JSC implements Promise.try()
in an ECMAScript-way
Does Cancellation in Promise dream of implementation on the JS side?!
Thank you for listening!
I hope you catch("key points")
well!
8 years ago, I was in junior high or high school
Of the four major browsers, two have implemented it, and Safari is just lagging behind, but it is already implemented in JSC, which I will introduce today
Since synchronous functions are not thenable, to .then(), you must create a Promise with Promise.resolve() and then execute it with .then()
Create a new Promise
Resolve the result of syncOrAsync() as is
Complete the Promise as successful
If syncOrAsync() returns a synchronous value or a Promise, the result is passed to .then(console.log) and output to the console
If syncOrAsync() throws an error or the returned Promise is rejected, the error is output to the console by .catch(console.error)
The Promise is resolved immediately, so unnecessary asynchronous processing does not occur
As you can see, handling synchronous and asynchronous processing uniformly in JavaScript has been a difficult problem, requiring verbose writing styles or unnecessary event loops.
How did existing libraries achieve Promise.try in JavaScript?
An article by someone who initially pushed for Promise.try
Before looking at the JS engine implementation, let's look at the ECMAScript specification for Promise.try, which serves as its blueprint
JSCではビルトイン関数をC++で書くこともできるし、JSで書くこともできる。そして Promise.try は JS で書かれている
`arguments`というArrayLike を args 配列に詰め直してるだけ
仕様では、Completionという概念を使ってエラーハンドリングがなされていたが、JSCのコードではJSの普通のtry-catchのエラーハンドリングとして実現されている
Completionみたいな概念は現れていないことを補足する