Skip to content
This repository
Newer
Older
100644 471 lines (395 sloc) 13.407 kb
ab566f83 »
2011-01-23 npm package
1 fibers(1) -- Fiber support for v8 and Node
2 ==========================================
a9e6241d »
2011-01-22 README update
3
ab566f83 »
2011-01-23 npm package
4 INSTALLING
5 ----------
a9e6241d »
2011-01-22 README update
6
b9ca1432 »
2012-01-04 Documentation updates
7 ### via npm
a0f797c5 »
2011-08-13 Documentation updates
8 * `npm install fibers`
9 * You're done!
a9e6241d »
2011-01-22 README update
10
b9ca1432 »
2012-01-04 Documentation updates
11 ### from source
9d9efdd2 »
2012-05-09 Port build to gyp + setup for binary distribution
12 * `git clone git://github.com/laverdet/node-fibers.git`
13 * `cd node-fibers`
e034e26e »
2012-05-11 Minor documentation updates
14 * `npm install`
15
16 Note: node-fibers uses [node-gyp](https://github.com/TooTallNate/node-gyp) for
17 building. To manually invoke the build process, you can use `node-gyp rebuild`.
1760f9a0 »
2012-06-24 Distinct binaries for v8 versions
18 This will put the compiled extension in `build/Release/fibers.node`. However,
19 when you do `require('fibers')`, it will expect the module to be in, for
20 example, `bin/linux-x64-v8-3.11/fibers.node`. You can manually put the module
21 here every time you build, or you can use the included build script. Either
22 `npm install` or `node build -f` will do this for you. If you are going to be
23 hacking on node-fibers, it may be worthwhile to first do `node-gyp configure`
24 and then for subsequent rebuilds you can just do `node-gyp build` which will
25 be faster than a full `npm install` or `node-gyp rebuild`.
a9e6241d »
2011-01-22 README update
26
9d9efdd2 »
2012-05-09 Port build to gyp + setup for binary distribution
27 ### important!
e034e26e »
2012-05-11 Minor documentation updates
28 It's recommended that you use node 0.6.18 or higher with node-fibers. Using
29 other versions may lead to instability during high loads.
9d9efdd2 »
2012-05-09 Port build to gyp + setup for binary distribution
30
9beaa7a3 »
2012-06-24 Add a quick note about Windows 8 to readme
31 ### using windows 8?
32 Windows 8 is a beta operating system and you may have issues with fibers. To use
33 fibers in Windows 8 you may need to run node.exe in Windows 7 compatibility
34 mode. Once Windows 8 is released this issue will be revisited. See gh-70 for
35 more information.
36
9d9efdd2 »
2012-05-09 Port build to gyp + setup for binary distribution
37 ### other notes
38 Unlike most NodeJS projects, node-fibers is a C++ project. Some extra work is
39 required to compile node-fibers, but pretty much every platform is supported
40 in some way. Binary distributions in 32 and 64-bit forms are provided in npm for
41 Linux, OS X, and Windows (special thanks to
42 [Jeroen Janssen](https://github.com/japj) for his work on fibers in Windows).
43
44 Support for Solaris, FreeBSD, and OpenBSD is provided by compiling the extension
45 on your system during install time via
46 [node-gyp](https://github.com/TooTallNate/node-gyp). If your operating system
47 isn't listed here you may have luck copying the build process for one of the
48 other OS's, assuming you are running a POSIX-like OS.
49
50 node 0.6.x is required to run this release of node-fibers. Older versions of
b9ca1432 »
2012-01-04 Documentation updates
51 node (0.4.x) are supported in older releases of node-fibers. See the 0.5.x
9d9efdd2 »
2012-05-09 Port build to gyp + setup for binary distribution
52 branch of node-fibers for documentation.
ab566f83 »
2011-01-23 npm package
53
54
55 EXAMPLES
56 --------
57
0685a72c »
2011-07-26 Documentation updates
58 The examples below describe basic use of `Fiber`, but note that it is **not
59 recommended** to use `Fiber` without an abstraction in between your code and
60 fibers. See "FUTURES" below for additional information.
61
5a8946ae »
2011-08-06 Documentation updates
62 ### Sleep
ab566f83 »
2011-01-23 npm package
63 This is a quick example of how you can write sleep() with fibers. Note that
64 while the sleep() call is blocking inside the fiber, node is able to handle
65 other events.
a9e6241d »
2011-01-22 README update
66
ac01c73f »
2011-02-19 Spaces -> Tabs
67 $ cat sleep.js
a9e6241d »
2011-01-22 README update
68
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
69 ```javascript
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
70 var Fiber = require('fibers');
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
71
72 function sleep(ms) {
73 var fiber = Fiber.current;
74 setTimeout(function() {
75 fiber.run();
76 }, ms);
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
77 Fiber.yield();
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
78 }
79
80 Fiber(function() {
81 console.log('wait... ' + new Date);
82 sleep(1000);
83 console.log('ok... ' + new Date);
84 }).run();
85 console.log('back in main');
86 ```
a9e6241d »
2011-01-22 README update
87
a0f797c5 »
2011-08-13 Documentation updates
88 $ node sleep.js
ac01c73f »
2011-02-19 Spaces -> Tabs
89 wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
90 back in main
91 ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
a9e6241d »
2011-01-22 README update
92
ab566f83 »
2011-01-23 npm package
93
5a8946ae »
2011-08-06 Documentation updates
94 ### Incremental Generator
a9e6241d »
2011-01-22 README update
95 Yielding execution will resume back in the fiber right where you left off. You
0685a72c »
2011-07-26 Documentation updates
96 can also pass values back and forth through yield() and run(). Again, the node
97 event loop is never blocked while this script is running.
a9e6241d »
2011-01-22 README update
98
ac01c73f »
2011-02-19 Spaces -> Tabs
99 $ cat generator.js
100
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
101 ```javascript
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
102 var Fiber = require('fibers');
ac01c73f »
2011-02-19 Spaces -> Tabs
103
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
104 var inc = Fiber(function(start) {
105 var total = start;
106 while (true) {
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
107 total += Fiber.yield(total);
ac01c73f »
2011-02-19 Spaces -> Tabs
108 }
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
109 });
110
111 for (var ii = inc.run(1); ii <= 10; ii = inc.run(1)) {
112 console.log(ii);
113 }
114 ```
ac01c73f »
2011-02-19 Spaces -> Tabs
115
a0f797c5 »
2011-08-13 Documentation updates
116 $ node generator.js
ac01c73f »
2011-02-19 Spaces -> Tabs
117 1
118 2
119 3
120 4
121 5
122 6
123 7
124 8
125 9
126 10
a9e6241d »
2011-01-22 README update
127
ab566f83 »
2011-01-23 npm package
128
5a8946ae »
2011-08-06 Documentation updates
129 ### Fibonacci Generator
130 Expanding on the incremental generator above, we can create a generator which
131 returns a new Fibonacci number with each invocation. You can compare this with
132 the [ECMAScript Harmony
133 Generator](http://wiki.ecmascript.org/doku.php?id=harmony:generators) Fibonacci
134 example.
135
136 $ cat fibonacci.js
137
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
138 ```javascript
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
139 var Fiber = require('fibers');
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
140
141 // Generator function. Returns a function which returns incrementing
142 // Fibonacci numbers with each call.
143 function Fibonacci() {
144 // Create a new fiber which yields sequential Fibonacci numbers
145 var fiber = Fiber(function() {
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
146 Fiber.yield(0); // F(0) -> 0
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
147 var prev = 0, curr = 1;
148 while (true) {
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
149 Fiber.yield(curr);
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
150 var tmp = prev + curr;
151 prev = curr;
152 curr = tmp;
153 }
154 });
155 // Return a bound handle to `run` on this fiber
156 return fiber.run.bind(fiber);
157 }
158
159 // Initialize a new Fibonacci sequence and iterate up to 1597
160 var seq = Fibonacci();
161 for (var ii = seq(); ii <= 1597; ii = seq()) {
162 console.log(ii);
163 }
164 ```
5a8946ae »
2011-08-06 Documentation updates
165
a0f797c5 »
2011-08-13 Documentation updates
166 $ node fibonacci.js
5a8946ae »
2011-08-06 Documentation updates
167 0
168 1
169 1
170 2
171 3
172 5
173 8
174 13
175 21
176 34
177 55
178 89
179 144
180 233
181 377
182 610
183 987
184 1597
185
186
187 ### Basic Exceptions
041247c8 »
2011-01-22 Documentation and other inconsequential changes
188 Fibers are exception-safe; exceptions will continue travelling through fiber
189 boundaries:
190
ac01c73f »
2011-02-19 Spaces -> Tabs
191 $ cat error.js
192
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
193 ```javascript
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
194 var Fiber = require('fibers');
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
195
196 var fn = Fiber(function() {
197 console.log('async work here...');
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
198 Fiber.yield();
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
199 console.log('still working...');
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
200 Fiber.yield();
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
201 console.log('just a little bit more...');
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
202 Fiber.yield();
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
203 throw new Error('oh crap!');
204 });
205
206 try {
207 while (true) {
208 fn.run();
ac01c73f »
2011-02-19 Spaces -> Tabs
209 }
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
210 } catch(e) {
211 console.log('safely caught that error!');
212 console.log(e.stack);
213 }
214 console.log('done!');
215 ```
ac01c73f »
2011-02-19 Spaces -> Tabs
216
a0f797c5 »
2011-08-13 Documentation updates
217 $ node error.js
ac01c73f »
2011-02-19 Spaces -> Tabs
218 async work here...
219 still working...
220 just a little bit more...
221 safely caught that error!
222 Error: oh crap!
223 at error.js:11:9
224 done!
041247c8 »
2011-01-22 Documentation and other inconsequential changes
225
ab566f83 »
2011-01-23 npm package
226
0685a72c »
2011-07-26 Documentation updates
227 FUTURES
228 -------
ac01c73f »
2011-02-19 Spaces -> Tabs
229
0685a72c »
2011-07-26 Documentation updates
230 Using the `Fiber` class without an abstraction in between your code and the raw
231 API is **not recommended**. `Fiber` is meant to implement the smallest amount of
232 functionality in order make possible many different programming patterns. This
233 makes the `Fiber` class relatively lousy to work with directly, but extremely
234 powerful when coupled with a decent abstraction. There is no right answer for
235 which abstraction is right for you and your project. Included with `node-fibers`
b9ca1432 »
2012-01-04 Documentation updates
236 is an implementation of "futures" which is fiber-aware. Usage of this library
237 is documented below. There are several other externally-maintained options
238 which can be found on the [wiki](https://github.com/laverdet/node-fibers/wiki).
239 You **should** feel encouraged to be creative with fibers and build a solution
5a8946ae »
2011-08-06 Documentation updates
240 which works well with your project. For instance, `Future` is not a good
241 abstraction to use if you want to build a generator function (see Fibonacci
242 example above).
ac01c73f »
2011-02-19 Spaces -> Tabs
243
0685a72c »
2011-07-26 Documentation updates
244 Using `Future` to wrap existing node functions. At no point is the node event
245 loop blocked:
ac01c73f »
2011-02-19 Spaces -> Tabs
246
0685a72c »
2011-07-26 Documentation updates
247 $ cat ls.js
ac01c73f »
2011-02-19 Spaces -> Tabs
248
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
249 ```javascript
250 var Future = require('fibers/future'), wait = Future.wait;
251 var fs = require('fs');
252
253 // This wraps existing functions assuming the last argument of the passed
254 // function is a callback. The new functions created immediately return a
255 // future and the future will resolve when the callback is called (which
256 // happens behind the scenes).
257 var readdir = Future.wrap(fs.readdir);
258 var stat = Future.wrap(fs.stat);
259
260 Fiber(function() {
261 // Get a list of files in the directory
262 var fileNames = readdir('.').wait();
263 console.log('Found '+ fileNames.length+ ' files');
264
265 // Stat each file
266 var stats = [];
267 for (var ii = 0; ii < fileNames.length; ++ii) {
268 stats.push(stat(fileNames[ii]));
269 }
270 wait(stats);
271
272 // Print file size
273 for (var ii = 0; ii < fileNames.length; ++ii) {
274 console.log(fileNames[ii]+ ': '+ stats[ii].get().size);
275 }
276 }).run();
277 ```
ac01c73f »
2011-02-19 Spaces -> Tabs
278
a0f797c5 »
2011-08-13 Documentation updates
279 $ node ls.js
0685a72c »
2011-07-26 Documentation updates
280 Found 11 files
281 bin: 4096
282 fibers.js: 1708
283 .gitignore: 37
284 README.md: 8664
285 future.js: 5833
286 .git: 4096
287 LICENSE: 1054
288 src: 4096
289 ls.js: 860
290 Makefile: 436
291 package.json: 684
292
293
294 The future API is designed to make it easy to move between classic
295 callback-style code and fiber-aware waiting code:
296
297 $ cat sleep.js
298
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
299 ```javascript
300 var Future = require('fibers/future'), wait = Future.wait;
301
302 // This function returns a future which resolves after a timeout. This
303 // demonstrates manually resolving futures.
304 function sleep(ms) {
305 var future = new Future;
306 setTimeout(function() {
307 future.return();
308 }, ms);
309 return future;
310 }
311
312 // You can create functions which automatically run in their own fiber and
313 // return futures that resolve when the fiber returns (this probably sounds
314 // confusing.. just play with it to understand).
315 var calcTimerDelta = function(ms) {
316 var start = new Date;
317 sleep(ms).wait();
318 return new Date - start;
319 }.future(); // <-- important!
320
321 // And futures also include node-friendly callbacks if you don't want to use
322 // wait()
323 calcTimerDelta(2000).resolve(function(err, val) {
324 console.log('Set timer for 2000ms, waited '+ val+ 'ms');
325 });
326 ```
0685a72c »
2011-07-26 Documentation updates
327
a0f797c5 »
2011-08-13 Documentation updates
328 $ node sleep.js
0685a72c »
2011-07-26 Documentation updates
329 Set timer for 2000ms, waited 2009ms
a9e6241d »
2011-01-22 README update
330
ab566f83 »
2011-01-23 npm package
331
0685a72c »
2011-07-26 Documentation updates
332 API DOCUMENTATION
333 -----------------
a9e6241d »
2011-01-22 README update
334 Fiber's definition looks something like this:
335
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
336 ```javascript
337 /**
338 * Instantiate a new Fiber. You may invoke this either as a function or as
339 * a constructor; the behavior is the same.
340 *
341 * When run() is called on this fiber for the first time, `fn` will be
342 * invoked as the first frame on a new stack. Execution will continue on
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
343 * this new stack until `fn` returns, or Fiber.yield() is called.
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
344 *
345 * After the function returns the fiber is reset to original state and
346 * may be restarted with another call to run().
347 */
348 function Fiber(fn) {
349 [native code]
350 }
351
352 /**
353 * `Fiber.current` will contain the currently-running Fiber. It will be
354 * `undefined` if there is no fiber (i.e. the main stack of execution).
355 *
356 * See "Garbage Collection" for more information on responsible use of
357 * `Fiber.current`.
358 */
359 Fiber.current = undefined;
360
361 /**
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
362 * `Fiber.yield()` will halt execution of the current fiber and return control
363 * back to original caller of run(). If an argument is supplied to yield(),
364 * run() will return that value.
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
365 *
366 * When run() is called again, yield() will return.
367 *
368 * Note that this function is a global to allow for correct garbage
369 * collection. This results in no loss of functionality because it is only
370 * valid to yield from the currently running fiber anyway.
371 *
372 * Note also that `yield` is a reserved word in Javascript. This is normally
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
373 * not an issue, however some code linters may complain. Rest assured that it
374 * will run fine now and in future versions of Javascript.
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
375 */
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
376 Fiber.yield = function(param) {
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
377 [native code]
378 }
379
380 /**
381 * run() will start execution of this Fiber, or if it is currently yielding,
382 * it will resume execution. If an argument is supplied, this argument will
383 * be passed to the fiber, either as the first parameter to the main
384 * function [if the fiber has not been started] or as the return value of
385 * yield() [if the fiber is currently yielding].
386 *
387 * This function will return either the parameter passed to yield(), or the
388 * returned value from the fiber's main function.
389 */
390 Fiber.prototype.run = function(param) {
391 [native code]
392 }
393
394 /**
395 * reset() will terminate a running Fiber and restore it to its original
396 * state, as if it had returned execution.
397 *
398 * This is accomplished by causing yield() to throw an exception, and any
399 * futher calls to yield() will also throw an exception. This continues
400 * until the fiber has completely unwound and returns.
401 *
402 * If the fiber returns a value it will be returned by reset().
403 *
404 * If the fiber is not running, reset() will have no effect.
405 */
406 Fiber.prototype.reset = function() {
407 [native code]
408 }
409
410 /**
411 * throwInto() will cause a currently yielding fiber's yield() call to
412 * throw instead of return gracefully. This can be useful for notifying a
413 * fiber that you are no longer interested in its task, and that it should
414 * give up.
415 *
416 * Note that if the fiber does not handle the exception it will continue to
417 * bubble up and throwInto() will throw the exception right back at you.
418 */
419 Fiber.prototype.throwInto = function(exception) {
420 [native code]
421 }
422 ```
a9e6241d »
2011-01-22 README update
423
ab566f83 »
2011-01-23 npm package
424 GARBAGE COLLECTION
a9e6241d »
2011-01-22 README update
425 ------------------
426
5a8946ae »
2011-08-06 Documentation updates
427 If you intend to build generators, iterators, or "lazy lists", you should be
428 aware that all fibers must eventually unwind. This is implemented by causing
429 yield() to throw unconditionally when the library is trying to unwind your
430 fiber-- either because reset() was called, or all handles to the fiber were lost
431 and v8 wants to delete it.
a9e6241d »
2011-01-22 README update
432
433 Something like this will, at some point, cause an infinite loop in your
434 application:
435
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
436 ```javascript
437 var fiber = Fiber(function() {
438 while (true) {
439 try {
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
440 Fiber.yield();
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
441 } catch(e) {}
442 }
443 });
444 fiber.run();
445 ```
a9e6241d »
2011-01-22 README update
446
447 If you either call reset() on this fiber, or the v8 garbage collector decides it
448 is no longer in use, the fiber library will attempt to unwind the fiber by
449 causing all calls to yield() to throw. However, if you catch these exceptions
450 and continue anyway, an infinite loop will occur.
451
452 There are other garbage collection issues that occur with misuse of fiber
453 handles. If you grab a handle to a fiber from within itself, you should make
454 sure that the fiber eventually unwinds. This application will leak memory:
455
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
456 ```javascript
457 var fiber = Fiber(function() {
458 var that = Fiber.current;
5d04e850 »
2012-05-08 Begin transition to non-global Fiber object
459 Fiber.yield();
9e00a064 »
2011-09-30 GitHub flavored Markdown syntax highlighter
460 }
461 fiber.run();
462 fiber = undefined;
463 ```
a9e6241d »
2011-01-22 README update
464
465 There is no way to get back into the fiber that was started, however it's
466 impossible for v8's garbage collector to detect this. With a handle to the fiber
467 still outstanding, v8 will never garbage collect it and the stack will remain in
468 memory until the application exits.
469
470 Thus, you should take care when grabbing references to `Fiber.current`.
Something went wrong with that request. Please try again.