|
1 | | -# template-for-proposals |
| 1 | +# [Promise.isPromise]() |
2 | 2 |
|
3 | | -A repository template for ECMAScript proposals. |
| 3 | +ECMAScript proposal and spec for `Promise.isPromise`. |
4 | 4 |
|
5 | | -## Before creating a proposal |
| 5 | +## Status |
6 | 6 |
|
7 | | -Please ensure the following: |
8 | | - 1. You have read the [process document](https://tc39.github.io/process-document/) |
9 | | - 1. You have reviewed the [existing proposals](https://github.com/tc39/proposals/) |
10 | | - 1. You are aware that your proposal requires being a member of TC39, or locating a TC39 delegate to “champion” your proposal |
| 7 | +[The TC39 Process](https://tc39.es/process-document/) |
11 | 8 |
|
12 | | -## Create your proposal repo |
| 9 | +**Stage**: 0 |
13 | 10 |
|
14 | | -Follow these steps: |
15 | | - 1. Click the green [“use this template”](https://github.com/tc39/template-for-proposals/generate) button in the repo header. (Note: Do not fork this repo in GitHub's web interface, as that will later prevent transfer into the TC39 organization) |
16 | | - 1. Update ecmarkup and the biblio to the latest version: `npm install --save-dev ecmarkup@latest && npm install --save-dev --save-exact @tc39/ecma262-biblio@latest`. |
17 | | - 1. Go to your repo settings page: |
18 | | - 1. Under “General”, under “Features”, ensure “Issues” is checked, and disable “Wiki”, and “Projects” (unless you intend to use Projects) |
19 | | - 1. Under “Pull Requests”, check “Always suggest updating pull request branches” and “automatically delete head branches” |
20 | | - 1. Under the “Pages” section on the left sidebar, and set the source to “deploy from a branch”, select “gh-pages” in the branch dropdown, and then ensure that “Enforce HTTPS” is checked. |
21 | | - 1. Under the “Actions” section on the left sidebar, under “General”, select “Read and write permissions” under “Workflow permissions” and click “Save” |
22 | | - 1. [“How to write a good explainer”][explainer] explains how to make a good first impression. |
| 11 | +**Champions**: |
| 12 | +- Mathieu Hofman ([@mhofman](https://github.com/mhofman)) (Agoric) |
23 | 13 |
|
24 | | - > Each TC39 proposal should have a `README.md` file which explains the purpose |
25 | | - > of the proposal and its shape at a high level. |
26 | | - > |
27 | | - > ... |
28 | | - > |
29 | | - > The rest of this page can be used as a template ... |
| 14 | +## Motivation |
30 | 15 |
|
31 | | - Your explainer can point readers to the `index.html` generated from `spec.emu` |
32 | | - via markdown like |
| 16 | +It is currently impossible to check whether an object is a native promise without side effects. The usual pattern is to test whether `Promise.resolve(val) === val`, but in the negative case it creates a new promise resolved from `val`. Besides the unnecessary allocation, it may also trigger user-code related to the [thenable assimilation mechanism](https://promisesaplus.com/#the-then-method). |
33 | 17 |
|
34 | | - ```markdown |
35 | | - You can browse the [ecmarkup output](https://ACCOUNT.github.io/PROJECT/) |
36 | | - or browse the [source](https://github.com/ACCOUNT/PROJECT/blob/HEAD/spec.emu). |
37 | | - ``` |
| 18 | +Code that wants to be defensive, for example avoid synchronous re-entrancy when handling unknown values in async logic, can currently only do so by paying the cost of a tick (`Promise.resolve().then(() => val)`), even when the value is a safe native promise. |
38 | 19 |
|
39 | | - where *ACCOUNT* and *PROJECT* are the first two path elements in your project's Github URL. |
40 | | - For example, for github.com/**tc39**/**template-for-proposals**, *ACCOUNT* is “tc39” |
41 | | - and *PROJECT* is “template-for-proposals”. |
| 20 | +Native promises have their internal state safely adopted when doing `await val`, and if https://github.com/tc39/ecma262/pull/3689 is accepted, for other promise resolution paths. |
42 | 21 |
|
| 22 | +`instanceof Promise` is not appropriate because that checks whether `Promise.prototype` is in the prototype chain of value, not whether the value passes the the `IsPromise` checks the spec performs internally. |
43 | 23 |
|
44 | | -## Maintain your proposal repo |
| 24 | +## Proposal |
45 | 25 |
|
46 | | - 1. Make your changes to `spec.emu` (ecmarkup uses HTML syntax, but is not HTML, so I strongly suggest not naming it “.html”) |
47 | | - 1. Any commit that makes meaningful changes to the spec, should run `npm run build` to verify that the build will succeed and the output looks as expected. |
48 | | - 1. Whenever you update `ecmarkup`, run `npm run build` to verify that the build will succeed and the output looks as expected. |
| 26 | +A new `Promise.isPromise` predicate that exposes the result of the [`IsPromise`](https://tc39.es/ecma262/#sec-ispromise) abstract operation. |
49 | 27 |
|
50 | | - [explainer]: https://github.com/tc39/how-we-work/blob/HEAD/explainer.md |
| 28 | +## Precedent |
| 29 | + |
| 30 | +[`Error.isError`](https://github.com/tc39/proposal-is-error) does a similar brand check for native `Error` objects. |
| 31 | + |
| 32 | +## Membrane transparency |
| 33 | + |
| 34 | +Like `Error`, `Promise`s are also objects which are better "passed by copy" than proxied through membranes. Furthermore, it is already possible to asynchronously detect whether an object is a native promise or not through `Promise.resolve()`. |
| 35 | + |
| 36 | +A `Promise.isPromise` predicate would actually let membranes detect promise values which should be recreated on the other side. |
0 commit comments