@@ -16,6 +16,14 @@ involved in the AsyncWrap API._
16
16
17
17
For the remaining description the API part is what is meant by AsyncWrap.
18
18
19
+ ## Table of Content
20
+
21
+ * [ Handle Objects] ( #handle-objects )
22
+ * [ The API] ( #the-api )
23
+ * [ Example] ( #example )
24
+ * [ Things You Might Not Expect] ( #things-you-might-not-expect )
25
+ * [ Resources] ( #resources )
26
+
19
27
## Handle Objects
20
28
21
29
AsyncWrap emits events (hooks) that inform the consumer about the life of all
@@ -42,41 +50,53 @@ req.port = port;
42
50
const socket = new TCP ();
43
51
socket .onread = onread;
44
52
socket .connect (req, address, port);
53
+
54
+ // later
55
+ socket .destroy ();
45
56
```
46
57
47
- The first one (` TCPConnectWrap ` ) is for connecting the socket, the second
48
- one (` TCP ` ) is for maintaining the connection.
58
+ The first handle object (` TCPConnectWrap ` ) is for connecting the socket, the
59
+ second one (` TCP ` ) is for maintaining the connection.
49
60
50
61
` TCPConnectWrap ` gets its information by setting properties on the handle
51
62
object, like ` address ` and ` port ` . Those properties are read by the C++ layer,
52
63
but can also be inspected from the AsyncWrap hooks. When the handle is created
53
64
using ` new TCPConnectWrap() ` the ` init ` hook is called.
54
65
55
- A ` oncomplete ` property is also set, this is the callback for when the
56
- connection is made or failed. Just before calling ` oncomplete ` the ` before ` hook
57
- is called, just after the ` after ` hook is called.
66
+ An ` oncomplete ` property is also set, this is the callback for when the
67
+ connection is made or failed. Just before calling ` oncomplete ` the ` pre ` hook
68
+ is called, just after the ` post ` hook is called.
58
69
59
70
The ` TCP ` handle works exactly the same way, except that the information
60
71
is passed as arguments to a method ` .connect ` and the ` onread ` function
61
72
is called multiple times, thus it behaves like an event. This also means that
62
- the ` before ` and ` after ` hooks are called multiple times.
73
+ the ` pre ` and ` post ` hooks are called multiple times.
74
+
75
+ At some later time the ` socket.destroy() ` is called, this will call the
76
+ ` destroy ` hook for the ` socket ` handle. Other handle objects aren't explicitly
77
+ destroyed, in that case the ` destroy ` hook is called when the handle object is
78
+ garbage collected by v8.
63
79
64
80
Thus one should expect the hooks be called in the following order:
65
81
66
82
``` javascript
67
83
init // TCPConnectWrap
68
84
init // TCP
69
85
=== tick ===
70
- before // TCPConnectWrap
71
- after // TCPConnectWrap
86
+ pre // TCPConnectWrap
87
+ post // TCPConnectWrap
72
88
=== tick ===
73
- before // TCP
74
- after // TCP
89
+ pre // TCP
90
+ post // TCP
75
91
=== tick ===
76
- before // TCP
77
- after // TCP
92
+ pre // TCP
93
+ post // TCP
78
94
=== tick ===
79
95
...
96
+ === tick ===
97
+ destroy // TCP
98
+ === tick ===
99
+ destroy // TCPConnectWrap
80
100
```
81
101
82
102
_ tick_ indicates there is at least one tick (as in ` process.nextTick() ` ) between
@@ -97,14 +117,15 @@ if it's just patch update._
97
117
To assign the hooks call:
98
118
99
119
``` javascript
100
- asyncWrap .setupHooks (init, before, after);
101
- function init (provider , parent ) { /* consumer code */ }
102
- function before () { /* consumer code */ }
103
- function after () { /* consumer code */ }
120
+ asyncWrap .setupHooks (init, pre, post, destroy);
121
+ function init (provider , uid , parent ) { /* consumer code */ }
122
+ function pre () { /* consumer code */ }
123
+ function post () { /* consumer code */ }
124
+ function destroy (uid ) { /* consumer code */ }
104
125
```
105
126
106
- Note that calling ` asyncWrap.setupHooks ` again, will overwrite the previous
107
- hooks.
127
+ Note that only the ` init ` function is required and that calling
128
+ ` asyncWrap.setupHooks ` again will overwrite the previous hooks.
108
129
109
130
#### Enable And Disable
110
131
@@ -131,25 +152,33 @@ asyncWrap.disable();
131
152
132
153
#### The Hooks
133
154
134
- Currently there are 3 hooks: ` init ` , ` before ` and ` after ` . The function
135
- signatures are quite similar . The ` this ` variable refers to the handle object,
136
- and ` init ` hook has two extra arguments ` provider ` and ` parent ` .
155
+ Currently there are 4 hooks: ` init ` , ` pre ` , ` post ` ` destroy ` . The ` this `
156
+ variable refers to the handle object . The ` init ` hook has three extra arguments
157
+ ` provider ` , ` uid ` and ` parent ` . The ` destroy ` hook also has the ` uid ` argument .
137
158
138
159
``` javascript
139
- function init (provider , parent ) { }
140
- function before () { }
141
- function after () { }
160
+ function init (provider , uid , parent ) { }
161
+ function pre () { }
162
+ function post () { }
163
+ function destroy (uid ) { }
142
164
```
143
165
144
166
##### this
145
- In all cases the ` this ` variable is the handle object. Users may read properties
146
- from this object such as ` port ` and ` address ` in the ` TCPConnectWrap ` case,
147
- or set user specific properties. However in the ` init ` hook the object is not
148
- yet fully constructed, thus some properties are not safe to read. This causes
149
- problems when doing ` util.inspect(this) ` or similar.
167
+
168
+ In the ` init ` , ` pre ` and ` post ` cases the ` this ` variable is the handle object.
169
+ Users may read properties from this object such as ` port ` and ` address ` in the
170
+ ` TCPConnectWrap ` case, or set user specific properties.
171
+
172
+ In the ` init ` hook the handle object is not yet fully constructed, thus some
173
+ properties are not safe to read. This causes problems when doing
174
+ ` util.inspect(this) ` or similar.
175
+
176
+ In the ` destroy ` hook ` this ` is ` null ` , this is because the handle objects has
177
+ been deleted by the garbage collector and thus doesn't exists.
150
178
151
179
##### provider
152
- This is an integer that refer to names defined in an ` asyncWrap.Providers `
180
+
181
+ This is an integer that refer to names defined in the ` asyncWrap.Providers `
153
182
object map.
154
183
155
184
At the time of writing this is the current list:
@@ -180,6 +209,13 @@ At the time of writing this is the current list:
180
209
ZLIB : 22 }
181
210
```
182
211
212
+ ##### uid
213
+
214
+ The ` uid ` is a unique integer that identify each handle object. Because the
215
+ ` destroy ` hook isn't called with the handle object, this is particular useful
216
+ for storing information related to the handle object, that the user require in
217
+ the ` destroy ` hook.
218
+
183
219
##### parent
184
220
185
221
In some cases the handle was created from another handle object. In those
@@ -191,15 +227,14 @@ but when receiving new connection it creates another `TCP` handle that is
191
227
responsible for the new socket. It does this before emitting the ` onconnection `
192
228
handle event, thus the asyncWrap hooks are called in the following order:
193
229
194
- ```
195
230
``` javascript
196
231
init // TCP (socket)
197
- before // TCP (server)
198
- after // TCP (server)
232
+ pre // TCP (server)
233
+ post // TCP (server)
199
234
```
200
235
201
236
This means it is not possible to know in what handle context the new socket
202
- handle was created using the ` before ` and ` after ` hooks. However the
237
+ handle was created using the ` pre ` and ` post ` hooks. However the
203
238
` parent ` argument provides this information.
204
239
205
240
## Example
@@ -209,13 +244,13 @@ A classic use case for AsyncWrap is to create a long-stack-trace tool.
209
244
``` javascript
210
245
const asyncWrap = process .binding (' async_wrap' );
211
246
212
- asyncWrap .setupHooks (init, before, after );
247
+ asyncWrap .setupHooks (init, pre, post );
213
248
asyncWrap .enable ();
214
249
215
250
// global state variable, that contains the current stack trace
216
251
let currentStack = ' ' ;
217
252
218
- function init (provider , parent ) {
253
+ function init (provider , uid , parent ) {
219
254
// When a handle is created, collect the stack trace such that we later
220
255
// can see what involved the handle constructor.
221
256
const localStack = (new Error ()).stack .split (' \n ' ).slice (1 ).join (' \n ' );
@@ -225,13 +260,13 @@ function init(provider, parent) {
225
260
const extraStack = parent ? parent ._full_init_stack : currentStack;
226
261
this ._full_init_stack = localStack + ' \n ' + extraStack;
227
262
}
228
- function before () {
263
+ function pre () {
229
264
// A callback is about to be called, update the `currentStack` such that
230
265
// it is correct for when another handle is initialized or `getStack` is
231
266
// called.
232
267
currentStack = this ._full_init_stack ;
233
268
}
234
- function after () {
269
+ function post () {
235
270
// At the time of writing there are some odd cases where there is no handle
236
271
// context, this line prevents that from resulting in wrong stack trace. But
237
272
// the stack trace will be shorter compared to what ideally should happen.
@@ -272,12 +307,12 @@ for how to do it.
272
307
273
308
## Resources
274
309
310
+ * Status overview of AsyncWrap: https://github.com/nodejs/tracing-wg/issues/29
275
311
* An intro to AsyncWrap by Trevor Norris: http://blog.trevnorris.com/2015/02/asyncwrap-tutorial-introduction.html (outdated)
276
312
* Slides from a local talk Andreas Madsen did on AsyncWrap:
277
313
https://github.com/AndreasMadsen/talk-async-wrap (outdated)
278
- * There was also some discussion in [ issue #21 ] ( https://github.com/nodejs/tracing-wg/issues/21#issuecomment-142727693 ) .
279
314
* Complete (hopefully) long-stack-trace module that uses AsyncWrap: https://github.com/AndreasMadsen/trace
280
- * Visualization tool for AsyncWrap wrap : https://github.com/AndreasMadsen/dprof
315
+ * Visualization tool for AsyncWrap: https://github.com/AndreasMadsen/dprof
281
316
282
317
----
283
318
0 commit comments