Browse files

GitHub flavored Markdown syntax highlighter

  • Loading branch information...
1 parent 3b3bd73 commit 9e00a0643bf87c995f28170068ed045f4dbddd99 @akzhan akzhan committed with Sep 30, 2011
Showing with 242 additions and 219 deletions.
  1. +242 −219 README.md
View
461 README.md
@@ -53,22 +53,25 @@ while the sleep() call is blocking inside the fiber, node is able to handle
other events.
$ cat sleep.js
- require('fibers');
-
- function sleep(ms) {
- var fiber = Fiber.current;
- setTimeout(function() {
- fiber.run();
- }, ms);
- yield();
- }
- Fiber(function() {
- console.log('wait... ' + new Date);
- sleep(1000);
- console.log('ok... ' + new Date);
- }).run();
- console.log('back in main');
+```javascript
+require('fibers');
+
+function sleep(ms) {
+ var fiber = Fiber.current;
+ setTimeout(function() {
+ fiber.run();
+ }, ms);
+ yield();
+}
+
+Fiber(function() {
+ console.log('wait... ' + new Date);
+ sleep(1000);
+ console.log('ok... ' + new Date);
+}).run();
+console.log('back in main');
+```
$ node sleep.js
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
@@ -82,18 +85,21 @@ can also pass values back and forth through yield() and run(). Again, the node
event loop is never blocked while this script is running.
$ cat generator.js
- require('fibers');
- var inc = Fiber(function(start) {
- var total = start;
- while (true) {
- total += yield(total);
- }
- });
+```javascript
+require('fibers');
- for (var ii = inc.run(1); ii <= 10; ii = inc.run(1)) {
- console.log(ii);
+var inc = Fiber(function(start) {
+ var total = start;
+ while (true) {
+ total += yield(total);
}
+});
+
+for (var ii = inc.run(1); ii <= 10; ii = inc.run(1)) {
+ console.log(ii);
+}
+```
$ node generator.js
1
@@ -116,31 +122,34 @@ Generator](http://wiki.ecmascript.org/doku.php?id=harmony:generators) Fibonacci
example.
$ cat fibonacci.js
- require('fibers');
-
- // Generator function. Returns a function which returns incrementing
- // Fibonacci numbers with each call.
- function Fibonacci() {
- // Create a new fiber which yields sequential Fibonacci numbers
- var fiber = Fiber(function() {
- yield(0); // F(0) -> 0
- var prev = 0, curr = 1;
- while (true) {
- yield(curr);
- var tmp = prev + curr;
- prev = curr;
- curr = tmp;
- }
- });
- // Return a bound handle to `run` on this fiber
- return fiber.run.bind(fiber);
- }
- // Initialize a new Fibonacci sequence and iterate up to 1597
- var seq = Fibonacci();
- for (var ii = seq(); ii <= 1597; ii = seq()) {
- console.log(ii);
- }
+```javascript
+require('fibers');
+
+// Generator function. Returns a function which returns incrementing
+// Fibonacci numbers with each call.
+function Fibonacci() {
+ // Create a new fiber which yields sequential Fibonacci numbers
+ var fiber = Fiber(function() {
+ yield(0); // F(0) -> 0
+ var prev = 0, curr = 1;
+ while (true) {
+ yield(curr);
+ var tmp = prev + curr;
+ prev = curr;
+ curr = tmp;
+ }
+ });
+ // Return a bound handle to `run` on this fiber
+ return fiber.run.bind(fiber);
+}
+
+// Initialize a new Fibonacci sequence and iterate up to 1597
+var seq = Fibonacci();
+for (var ii = seq(); ii <= 1597; ii = seq()) {
+ console.log(ii);
+}
+```
$ node fibonacci.js
0
@@ -168,27 +177,30 @@ Fibers are exception-safe; exceptions will continue travelling through fiber
boundaries:
$ cat error.js
- require('fibers');
-
- var fn = Fiber(function() {
- console.log('async work here...');
- yield();
- console.log('still working...');
- yield();
- console.log('just a little bit more...');
- yield();
- throw new Error('oh crap!');
- });
- try {
- while (true) {
- fn.run();
- }
- } catch(e) {
- console.log('safely caught that error!');
- console.log(e.stack);
+```javascript
+require('fibers');
+
+var fn = Fiber(function() {
+ console.log('async work here...');
+ yield();
+ console.log('still working...');
+ yield();
+ console.log('just a little bit more...');
+ yield();
+ throw new Error('oh crap!');
+});
+
+try {
+ while (true) {
+ fn.run();
}
- console.log('done!');
+} catch(e) {
+ console.log('safely caught that error!');
+ console.log(e.stack);
+}
+console.log('done!');
+```
$ node error.js
async work here...
@@ -222,33 +234,36 @@ Using `Future` to wrap existing node functions. At no point is the node event
loop blocked:
$ cat ls.js
- var Future = require('fibers/future'), wait = Future.wait;
- var fs = require('fs');
-
- // This wraps existing functions assuming the last argument of the passed
- // function is a callback. The new functions created immediately return a
- // future and the future will resolve when the callback is called (which
- // happens behind the scenes).
- var readdir = Future.wrap(fs.readdir);
- var stat = Future.wrap(fs.stat);
-
- Fiber(function() {
- // Get a list of files in the directory
- var fileNames = readdir('.').wait();
- console.log('Found '+ fileNames.length+ ' files');
-
- // Stat each file
- var stats = [];
- for (var ii = 0; ii < fileNames.length; ++ii) {
- stats.push(stat(fileNames[ii]));
- }
- wait(stats);
- // Print file size
- for (var ii = 0; ii < fileNames.length; ++ii) {
- console.log(fileNames[ii]+ ': '+ stats[ii].get().size);
- }
- }).run();
+```javascript
+var Future = require('fibers/future'), wait = Future.wait;
+var fs = require('fs');
+
+// This wraps existing functions assuming the last argument of the passed
+// function is a callback. The new functions created immediately return a
+// future and the future will resolve when the callback is called (which
+// happens behind the scenes).
+var readdir = Future.wrap(fs.readdir);
+var stat = Future.wrap(fs.stat);
+
+Fiber(function() {
+ // Get a list of files in the directory
+ var fileNames = readdir('.').wait();
+ console.log('Found '+ fileNames.length+ ' files');
+
+ // Stat each file
+ var stats = [];
+ for (var ii = 0; ii < fileNames.length; ++ii) {
+ stats.push(stat(fileNames[ii]));
+ }
+ wait(stats);
+
+ // Print file size
+ for (var ii = 0; ii < fileNames.length; ++ii) {
+ console.log(fileNames[ii]+ ': '+ stats[ii].get().size);
+ }
+}).run();
+```
$ node ls.js
Found 11 files
@@ -269,32 +284,35 @@ The future API is designed to make it easy to move between classic
callback-style code and fiber-aware waiting code:
$ cat sleep.js
- var Future = require('fibers/future'), wait = Future.wait;
-
- // This function returns a future which resolves after a timeout. This
- // demonstrates manually resolving futures.
- function sleep(ms) {
- var future = new Future;
- setTimeout(function() {
- future.return();
- }, ms);
- return future;
- }
- // You can create functions which automatically run in their own fiber and
- // return futures that resolve when the fiber returns (this probably sounds
- // confusing.. just play with it to understand).
- var calcTimerDelta = function(ms) {
- var start = new Date;
- sleep(ms).wait();
- return new Date - start;
- }.future(); // <-- important!
-
- // And futures also include node-friendly callbacks if you don't want to use
- // wait()
- calcTimerDelta(2000).resolve(function(err, val) {
- console.log('Set timer for 2000ms, waited '+ val+ 'ms');
- });
+```javascript
+var Future = require('fibers/future'), wait = Future.wait;
+
+// This function returns a future which resolves after a timeout. This
+// demonstrates manually resolving futures.
+function sleep(ms) {
+ var future = new Future;
+ setTimeout(function() {
+ future.return();
+ }, ms);
+ return future;
+}
+
+// You can create functions which automatically run in their own fiber and
+// return futures that resolve when the fiber returns (this probably sounds
+// confusing.. just play with it to understand).
+var calcTimerDelta = function(ms) {
+ var start = new Date;
+ sleep(ms).wait();
+ return new Date - start;
+}.future(); // <-- important!
+
+// And futures also include node-friendly callbacks if you don't want to use
+// wait()
+calcTimerDelta(2000).resolve(function(err, val) {
+ console.log('Set timer for 2000ms, waited '+ val+ 'ms');
+});
+```
$ node sleep.js
Set timer for 2000ms, waited 2009ms
@@ -304,93 +322,94 @@ API DOCUMENTATION
-----------------
Fiber's definition looks something like this:
- /**
- * Instantiate a new Fiber. You may invoke this either as a function or as
- * a constructor; the behavior is the same.
- *
- * When run() is called on this fiber for the first time, `fn` will be
- * invoked as the first frame on a new stack. Execution will continue on
- * this new stack until `fn` returns, or yield() is called.
- *
- * After the function returns the fiber is reset to original state and
- * may be restarted with another call to run().
- */
- function Fiber(fn) {
- [native code]
- }
-
- /**
- * `Fiber.current` will contain the currently-running Fiber. It will be
- * `undefined` if there is no fiber (i.e. the main stack of execution).
- *
- * See "Garbage Collection" for more information on responsible use of
- * `Fiber.current`.
- */
- Fiber.current = undefined;
-
- /**
- * yield() will halt execution of the current fiber and return control back
- * to original caller of run(). If an argument is supplied to yield, run()
- * will return that value.
- *
- * When run() is called again, yield() will return.
- *
- * Note that this function is a global to allow for correct garbage
- * collection. This results in no loss of functionality because it is only
- * valid to yield from the currently running fiber anyway.
- *
- * Note also that `yield` is a reserved word in Javascript. This is normally
- * not an issue, however if using strict mode you will not be able to call
- * yield() globally. Instead call `Fiber.yield()`.
- */
- function yield(param) {
- [native code]
- }
- Fiber.yield = yield;
-
- /**
- * run() will start execution of this Fiber, or if it is currently yielding,
- * it will resume execution. If an argument is supplied, this argument will
- * be passed to the fiber, either as the first parameter to the main
- * function [if the fiber has not been started] or as the return value of
- * yield() [if the fiber is currently yielding].
- *
- * This function will return either the parameter passed to yield(), or the
- * returned value from the fiber's main function.
- */
- Fiber.prototype.run = function(param) {
- [native code]
- }
-
- /**
- * reset() will terminate a running Fiber and restore it to its original
- * state, as if it had returned execution.
- *
- * This is accomplished by causing yield() to throw an exception, and any
- * futher calls to yield() will also throw an exception. This continues
- * until the fiber has completely unwound and returns.
- *
- * If the fiber returns a value it will be returned by reset().
- *
- * If the fiber is not running, reset() will have no effect.
- */
- Fiber.prototype.reset = function() {
- [native code]
- }
-
- /**
- * throwInto() will cause a currently yielding fiber's yield() call to
- * throw instead of return gracefully. This can be useful for notifying a
- * fiber that you are no longer interested in its task, and that it should
- * give up.
- *
- * Note that if the fiber does not handle the exception it will continue to
- * bubble up and throwInto() will throw the exception right back at you.
- */
- Fiber.prototype.throwInto = function(exception) {
- [native code]
- }
-
+```javascript
+/**
+ * Instantiate a new Fiber. You may invoke this either as a function or as
+ * a constructor; the behavior is the same.
+ *
+ * When run() is called on this fiber for the first time, `fn` will be
+ * invoked as the first frame on a new stack. Execution will continue on
+ * this new stack until `fn` returns, or yield() is called.
+ *
+ * After the function returns the fiber is reset to original state and
+ * may be restarted with another call to run().
+ */
+function Fiber(fn) {
+ [native code]
+}
+
+/**
+ * `Fiber.current` will contain the currently-running Fiber. It will be
+ * `undefined` if there is no fiber (i.e. the main stack of execution).
+ *
+ * See "Garbage Collection" for more information on responsible use of
+ * `Fiber.current`.
+ */
+Fiber.current = undefined;
+
+/**
+ * yield() will halt execution of the current fiber and return control back
+ * to original caller of run(). If an argument is supplied to yield, run()
+ * will return that value.
+ *
+ * When run() is called again, yield() will return.
+ *
+ * Note that this function is a global to allow for correct garbage
+ * collection. This results in no loss of functionality because it is only
+ * valid to yield from the currently running fiber anyway.
+ *
+ * Note also that `yield` is a reserved word in Javascript. This is normally
+ * not an issue, however if using strict mode you will not be able to call
+ * yield() globally. Instead call `Fiber.yield()`.
+ */
+function yield(param) {
+ [native code]
+}
+Fiber.yield = yield;
+
+/**
+ * run() will start execution of this Fiber, or if it is currently yielding,
+ * it will resume execution. If an argument is supplied, this argument will
+ * be passed to the fiber, either as the first parameter to the main
+ * function [if the fiber has not been started] or as the return value of
+ * yield() [if the fiber is currently yielding].
+ *
+ * This function will return either the parameter passed to yield(), or the
+ * returned value from the fiber's main function.
+ */
+Fiber.prototype.run = function(param) {
+ [native code]
+}
+
+/**
+ * reset() will terminate a running Fiber and restore it to its original
+ * state, as if it had returned execution.
+ *
+ * This is accomplished by causing yield() to throw an exception, and any
+ * futher calls to yield() will also throw an exception. This continues
+ * until the fiber has completely unwound and returns.
+ *
+ * If the fiber returns a value it will be returned by reset().
+ *
+ * If the fiber is not running, reset() will have no effect.
+ */
+Fiber.prototype.reset = function() {
+ [native code]
+}
+
+/**
+ * throwInto() will cause a currently yielding fiber's yield() call to
+ * throw instead of return gracefully. This can be useful for notifying a
+ * fiber that you are no longer interested in its task, and that it should
+ * give up.
+ *
+ * Note that if the fiber does not handle the exception it will continue to
+ * bubble up and throwInto() will throw the exception right back at you.
+ */
+Fiber.prototype.throwInto = function(exception) {
+ [native code]
+}
+```
GARBAGE COLLECTION
------------------
@@ -404,14 +423,16 @@ and v8 wants to delete it.
Something like this will, at some point, cause an infinite loop in your
application:
- var fiber = Fiber(function() {
- while (true) {
- try {
- yield();
- } catch(e) {}
- }
- });
- fiber.run();
+```javascript
+var fiber = Fiber(function() {
+ while (true) {
+ try {
+ yield();
+ } catch(e) {}
+ }
+});
+fiber.run();
+```
If you either call reset() on this fiber, or the v8 garbage collector decides it
is no longer in use, the fiber library will attempt to unwind the fiber by
@@ -422,12 +443,14 @@ There are other garbage collection issues that occur with misuse of fiber
handles. If you grab a handle to a fiber from within itself, you should make
sure that the fiber eventually unwinds. This application will leak memory:
- var fiber = Fiber(function() {
- var that = Fiber.current;
- yield();
- }
- fiber.run();
- fiber = undefined;
+```javascript
+var fiber = Fiber(function() {
+ var that = Fiber.current;
+ yield();
+}
+fiber.run();
+fiber = undefined;
+```
There is no way to get back into the fiber that was started, however it's
impossible for v8's garbage collector to detect this. With a handle to the fiber

0 comments on commit 9e00a06

Please sign in to comment.