├── GLOSSARY.md └── README.md /GLOSSARY.md: -------------------------------------------------------------------------------- 1 | # Glossary 2 | 3 | This is a glossary of terms that will be commonly used in discussion. This list 4 | will be expanded in the future. **Please avoid changing existing headings as 5 | users may be deep-linking to the generated anchors.** 6 | 7 | ## Table of Contents 8 | 9 | * [Error Symposium](#error-symposium) 10 | * [Operational Error](#operational-error) 11 | * [Programmer Error](#programmer-error) 12 | * [Post Mortem Analysis](#post-mortem-analysis) 13 | * [Abort](#abort) 14 | * [Core / Core dump / Core file](#core--core-dump--core-file) 15 | * [Stack Frame](#stack-frame) 16 | * [Unwinding the Stack / Top of Stack](#unwinding-the-stack--top-of-stack) 17 | * [Promise](#promise) 18 | * [Executor / Resolver](#executor--resolver) 19 | * [Handler](#handler) 20 | * [Settling](#settling) 21 | * [Rejection / reject](#rejection--reject) 22 | * [Resolving / resolve](#resolving--resolve) 23 | * [Synchronous Rejection](#synchronous-rejection) 24 | * [Unhandled Rejection / Rejection Handled](#unhandled-rejection--rejection-handled) 25 | * [Microtask Queue](#microtask-queue) 26 | * [Links](#links) 27 | 28 | ## Error Symposium 29 | 30 | An ongoing series of facilitated discussions led by **@groundwater**, originally 31 | conceived at the August 2015 Node Collaborator Summit at Mozilla SF. Their goal 32 | is to produce recommendations on "best practices" for error handling in Node. 33 | 34 | Notably, the conversation has been informed by the [foundational work][joyent-errors] 35 | written by **@davepacheco**. This document was paraphrased by **@chrisdickinson** as 36 | the part of the Node.js [error documentation][node-errors]. 37 | 38 | [The results of their latest meeting are here][symposium-findings]. 39 | 40 | ### Operational Error 41 | 42 | An error that represents a known state of the program. To paraphrase the 43 | [joyent error guide][joyent-errors]: 44 | 45 | > Operational errors represent run-time problems experienced by correctly-written 46 | > programs. These are not bugs in the program. In fact, these are usually 47 | > problems with something else: the system itself (e.g., out of memory or too 48 | > many open files), the system's configuration (e.g., no route to a remote host), 49 | > the network (e.g., socket hang-up), or a remote service (e.g., a 500 error, 50 | > failure to connect, or the like). 51 | 52 | ### Programmer Error 53 | 54 | An error that represents a mistake on the programmer's behalf. To paraphrase the 55 | [joyent error guide][joyent-errors]: 56 | 57 | > Programmer errors are bugs in the program. These are things that can always 58 | > be avoided by changing the code. They can never be handled properly (since by 59 | > definition the code in question is broken). 60 | 61 | #### A Note on Programmer/Operational Error Propagation 62 | 63 | These definitions do not describe the specific propagation method for these 64 | classes of errors. Either may appear as an error parameter to a nodeback 65 | function, or thrown by the API. The Error Symposium recommends only throwing 66 | on programmer error, while using the nodeback system to propagate operational 67 | errors. 68 | 69 | ## Post Mortem Analysis 70 | 71 | The practice of debugging a program after it has already crashed by inspecting 72 | the serialized state of the program at the time of error. This usually leverages 73 | tools like `lldb`, `gdb`, or `mdb` to inspect a "core" (defined below.) 74 | 75 | ### Abort 76 | 77 | The [`abort()`][abort-syscall] system call. Accessible to Node via 78 | `process.abort()`. Called by V8 when `--abort-on-uncaught-exception` is enabled 79 | and an exception is thrown without a top-level `catch` handler. 80 | 81 | Halts the program and serializes the state of the program (the contents of the 82 | stack and heap segments, as well as the state of open file descriptors) to a 83 | "core file." Causes the program to return a non-zero exit status. 84 | 85 | ### Core / Core dump / Core file 86 | 87 | The serialized state of a program, containing the stack and heap segments of 88 | memory in their entirety. Analyzable via `mdb`, `gdb`, or `lldb`. V8-specific 89 | plugins are available in the form of `mdb_v8`, `llnode`, and `lldb-v8`, and 90 | allow users to inspect JavaScript stack frames as well as the frozen object 91 | graph in memory (including objects pending garbage collection.) 92 | 93 | ### Stack Frame 94 | 95 | A data structure held in the stack segment of memory representing a function 96 | call. This typically saves the arguments with which the function was called 97 | as well as a return address to jump to when the call completes. 98 | 99 | ### Unwinding the Stack / Top of Stack 100 | 101 | Stack frames are collected into a stack that grows and shrinks as functions 102 | are called and functions return. Exceptions work by "unwinding" the stack 103 | to the nearest exception handler, if any — that is, they remove stack frames 104 | giving control back to the nearest frame with an exception handler. The 105 | stack is grown and shrunk in-place, so any subsequent function calls (even 106 | ones implicitly made by the JS VM) will clobber the original stack leading 107 | to the error. `Error` stacktraces _record_ some frame information leading to 108 | the error, but throwing an error is generally a lossy operation. 109 | 110 | If no exception handler is registered in a stack, instead of unwinding the 111 | stack, V8 may abort the program or call a user-defined `OnUncaughtException` 112 | handler. 113 | 114 | ## Promise 115 | 116 | The 30-second version: 117 | 118 | A [well-specified][promises-aplus] pattern that provides a container type 119 | designed to describe the dependence graph of asynchronous operations within a 120 | program. As a container type, any value `T` may be cast to an asynchronous 121 | value `Promise`. Any value `Promise` may be unwrapped to `T` by passing a 122 | handler (defined below) to `.then`. Unwrapping via `.then` creates a new 123 | `Promise` that will resolve to the return value of the handler. One promise may 124 | have zero-to-many child promises. 125 | 126 | Errors will propagate from a source promise to all child promises. If a 127 | rejected promise has no children, it is considered an unhandled rejection. It 128 | may be handled in a subsequent operation. If a promise has an error handler, 129 | propagation from source promises will halt at that promise. If a promise has 130 | many children, and only one handles errors, the other children will be 131 | unhandled rejections. 132 | 133 | Unwrapping `Promise>` will automatically unwrap to `T`. That is: 134 | `.then(() => Promise.resolve(3)).then(val => console.log(val))` will 135 | output `3`. 136 | 137 | Internally, a promise is represented by a state machine that may be in one of 138 | three states — pending, fulfilled, or rejected. The fulfilled and rejected 139 | states are collectively referred to as "settled." Once a promise is settled, it 140 | cannot transition into any other state. 141 | 142 | ### Executor / Resolver 143 | 144 | The function passed to the `new Promise` constructor. Run **synchronously**. 145 | Not in common direct use by most promise-users — used mainly to wrap sources of 146 | asynchrony. As such, it rarely resolves or rejects on the same tick. This API 147 | is provided for the express purpose of wrapping callback APIs. 148 | 149 | Catches all errors thrown. If an error is caught, the returned promise will be 150 | **rejected**. Because it starts life as a rejected promise with no children, it 151 | will immediately hit the `OnUnhandledRejection` callback. 152 | 153 | ```js 154 | new Promise(function Excecutor (resolve, reject) { 155 | // run immediately. 156 | }) 157 | ``` 158 | 159 | ### Handler 160 | 161 | A function passed to `Promise#then` or `Promise#catch`. If the function is 162 | passed as the first argument to `Promise#then`, it is a **fulfillment** 163 | handler. Otherwise, if it is passed to `.catch` or as the second argument to 164 | `.then`, it is a **rejection** handler. Fulfillment handlers are called with 165 | the resolved value of the parent promise. Rejection handlers are called with 166 | the error value of the parent promise. Calling `.then` or `.catch` on a Promise 167 | `A` returns a new `Promise`, which is a child of `A`. A handler which returns a 168 | value `T` or `Promise` will resolve the new promise with `T`. A handler 169 | which throws an error `R`, or returns a `Promise` which itself eventually 170 | rejects (or has already rejected) with `R`, will reject the new promise with 171 | `R`. 172 | 173 | ```js 174 | 175 | const p = new Promise(SomeOmittedExecutor) 176 | 177 | const p2 = p.then(function SuccessHandler(value) { 178 | // fired if p fulfills, 179 | }, function ErrorHandler(err) { 180 | // fired if p rejects. 181 | }) 182 | 183 | const p3 = p2.catch(function ErrorHandler(value) { 184 | // fired if p2 rejects. 185 | }) 186 | 187 | const p4 = p3.then(function SuccessHandler (value) { 188 | // resolved with p2's value if p2 resolves, 189 | // resolved with p3's value if p2 rejects and p3 resolves 190 | }) 191 | ``` 192 | 193 | ### Resolution / Settling 194 | 195 | The transition of a Promise from pending to a settled state, either "rejected" 196 | or "resolved." Once settled, a promise may never return to "pending" state. 197 | 198 | #### Rejection / reject 199 | 200 | The act of settling a promise with an error. Can be performed by the Executor 201 | or Handler `H` by throwing while `H` is on stack, or by resolving with a 202 | Promise that rejects at some point in its lifetime. In the case of Executors, 203 | rejection may additionally be achieved by calling the `reject` callback 204 | provided as an argument. 205 | 206 | Rejection is analogous to a synchronous `throw`. 207 | 208 | #### Fulfillment / resolve 209 | 210 | The act of settling a promise with a value. Can be performed by the Executor or 211 | a Handler. Executors may only resolve by calling the `resolve` callback 212 | provided to them as an argument, their return value is ignored. In the case of 213 | Handlers, fulfillment is achieved by returning a value from the Handler 214 | function. 215 | 216 | Fulfilling a Promise `A` using a Promise `B` will cause `A` to resolve or 217 | reject to the same value or error as `B`. The resolution of `A` is dependent on 218 | the resolution of `B`: if `B` never settles, `A` will never settle. The process 219 | of fulfilling a promise with another promise is known as "assimilation". 220 | 221 | ### Synchronous Rejection 222 | 223 | Sychronous rejection refers to the rare case where an executor is immediately 224 | rejected using `reject()` or `throw `. In the case of the 225 | proposed Node Promise API, only invalid API use will trigger a synchronous 226 | rejection. 227 | 228 | May also be triggered by the helper method, `Promise.reject()`. 229 | 230 | ### Unhandled Rejection / Rejection Handled 231 | 232 | Reported by the VM using `OnUnhandledRejection` and `OnRejectionHandled`. Called 233 | when a promise with no children is rejected. If the rejected promise is handled 234 | by a later operation, the `OnRejectionHandled` callback is called. A promise 235 | may synchronously transition from unhandled to handled: 236 | 237 | ```js 238 | const p1 = new Promise(() => { throw new Error('xyz')}) 239 | const p2 = p1.catch(err => { /* err === [Error: xyz] */ }) 240 | // calls executor 241 | // rejects 242 | // calls unhandled rejection with p1 and error 243 | // calls p2.catch 244 | // calls rejection handled with p1 245 | ``` 246 | 247 | Node currently [keeps track of extant rejections][rejection-pr], and fires 248 | `process.on('unhandledRejection')` for any rejections that have not been 249 | handled at the end of the microtask queue. 250 | 251 | ### Microtask Queue 252 | 253 | The Microtask Queue is a [specification-mandated queue][job-queue] of functions 254 | to be run at the exhaustion of a JavaScript stack. Promises feed into this 255 | queue: settled promises will enqueue a task to run handlers as they are added, 256 | pending promises with handlers will enqueue a task to run handlers when the 257 | promise settles. Other language-level features, like `Object.observe`, also 258 | feed into this queue. 259 | 260 | Currently this queue is opaque to Node. Node is not notified when new 261 | microtasks are queued, and Node may only tell V8 to run all of the microtasks 262 | queued to completion — it can't run them one at a time. 263 | 264 | ## Links 265 | 266 | * The public Microtask Queue API is defined [here][v8-public-microtask-api]. 267 | * V8's promise implementation is defined [here][v8-promise-implementation]. 268 | * `%EnqueueMicrotask` is defined [here][v8-intrinsic], and runs [this code][v8-private-microtask-api]. 269 | * V8's unhandled rejection API is defined [here][v8-unhandled-rejection-api]. 270 | * V8's abort on uncaught behavior is defined [here][v8-abort]. 271 | 272 | [v8-public-microtask-api]: https://github.com/v8/v8/blob/a26d0ac676ffc96a886e294728e69f5e7ba11b25/src/api.cc#L7399-L7414 273 | [v8-promise-implementation]: https://github.com/v8/v8/blob/a26d0ac676ffc96a886e294728e69f5e7ba11b25/src/js/promise.js 274 | [v8-intrinsic]: https://github.com/v8/v8/blob/a26d0ac676ffc96a886e294728e69f5e7ba11b25/src/runtime/runtime-observe.cc#L39 275 | [v8-private-microtask-api]: https://github.com/v8/v8/blob/a26d0ac676ffc96a886e294728e69f5e7ba11b25/src/isolate.cc#L2671-L2732 276 | [v8-unhandled-rejection-api]: https://github.com/v8/v8/blob/a26d0ac676ffc96a886e294728e69f5e7ba11b25/src/isolate.cc#L2652-L2668 277 | [v8-abort]: https://github.com/v8/v8/blob/a26d0ac676ffc96a886e294728e69f5e7ba11b25/src/isolate.cc#L1037-L1050 278 | [promises-aplus]: https://promisesaplus.com/ 279 | [abort-syscall]: http://man7.org/linux/man-pages/man3/abort.3.html 280 | [joyent-errors]: https://www.joyent.com/developers/node/design/errors 281 | [node-errors]: http://nodejs.org/api/errors.html 282 | [symposium-findings]: http://github.com/groundwater/nodejs-symposiums/ 283 | [rejection-pr]: https://github.com/nodejs/node/pull/758 284 | [job-queue]: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-jobs-and-job-queues 285 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # promises 2 | 3 | Promises Working Group Repository 4 | 5 | This repo serves as a central place for Node.js Promises work coordination. 6 | 7 | The Promises WG is dedicated to the support and improvement of Promises in Node.js 8 | core as well as the larger Node.js ecosystem. 9 | 10 | ## Lifecycle 11 | 12 | The concerns and responsibilities of this Working Group will change over time. There 13 | are three distinct stages of this WG: 14 | 15 | ### Stage 0: Landing a Flagged Promises API 16 | 17 | The first stage of this Working Group is focussed on the specifics of exposing a Promise 18 | API from Node core. The focus at this stage is in identifying blocking concerns raised 19 | by stakeholders, and triaging them into "blocking the landing of a flagged implementation", 20 | "blocking the unflagging of an implementation", and "non-blocking." 21 | 22 | You can track the status of these issues with the 23 | [`blocks-landing-pr`][issues-blocked-landing], 24 | [`blocks-unflagging`][issues-blocked-unflagging], and 25 | [`not-blocking`][issues-non-blocking] labels. 26 | 27 | **If you feel an issue is not appropriately blocking**, please raise your concern in the 28 | issue. 29 | 30 | When the issues marked [`blocks-landing-pr`][issues-blocked-landing] are all 31 | resolved, and the PR has been merged, this WG will move on to stage 1. 32 | 33 | ### Stage 1: Creating a Litmus test for Unflagging 34 | 35 | In this stage we will attempt to address all issues marked as 36 | [`blocks-unflagging`][issues-blocked-unflagging]. The focus of this stage will be 37 | to present an acceptable "go / no go" check for unflagging promises to the Node CTC. 38 | If accepted, once the "go / no go" check has passed, we will unflag the Promises API. 39 | 40 | Once the Promises API has landed, this WG will proceed to stage 2. 41 | 42 | ### Stage 2: Continued Support 43 | 44 | The WG will be available to support and advise the Core repository on matters 45 | related to promises. 46 | 47 | ### Membership 48 | 49 | Working Group Members: 50 | - @benjamingr 51 | - @refack 52 | - @petkaantonov 53 | - @vkurchatkin 54 | - @trevnorris 55 | - @kriskowal 56 | - @MadaraUchiha 57 | - @omsmith 58 | - @thefourtheye 59 | - @erights 60 | - @chrisdickinson 61 | 62 | # Participation 63 | 64 | We are currently looking for more participants in the working group - see https://github.com/nodejs/promises/issues/1 65 | 66 | [issues-blocked-landing]: https://github.com/nodejs/promises/issues?q=is%3Aopen+is%3Aissue+label%3Ablocks-landing-pr 67 | [issues-blocked-unflagging]: https://github.com/nodejs/promises/issues?q=is%3Aopen+is%3Aissue+label%3Ablocks-unflagging 68 | [issues-non-blocking]: https://github.com/nodejs/promises/issues?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue+label%3Anot-blocking 69 | --------------------------------------------------------------------------------