Fibers are not new invention
Node fibers make it possible to suspend the running of any function by saving the state of the current executing environment in a platform dependent way at the lowest level (For example windows has a fiber concept, not widely used, more lightweight than a thread, not preemptive).
Other libraries simulate co-routines using language features
All other js libraries implement co-routine continuation by using callback functions, storing the execution state in scope variables. This means you either have callback pyramid, a promise chain, or async/await (I put decorated generators in the same bucket as async/await).
Fibers are also a possible implementation of co-routines. Fibers should be fast, and integrating them in your code does not require you to write in a different codestyle, or introducing new syntax. Execution contexts (stack, registers, etc...) which can be changed to and from at will, from your own code.
This cannot be done in pure JavaScript, node-fibers use native libraries to achieve this!
Node fibers restrict you so you don't block the event loop
The node-fibers specific concept is: the javascript event loop is outside of all fibers, thus your initial code runs without fibers too. If you have a fiber reference, you can pass the right to run to it by fiber.run();
. When you are inside a fiber, you can give up the right to run by calling Fiber.yield();
(effectively suspending the currently running code), and the javascript event loop will continue. All builtin callbacks (setTimeout
, Promise.then
, event handlers, http request callbacks) will run in the javascript event loop, without a fiber.
See this example
const Fiber = require("fibers");
function findDataAsync(param, callback) {
setTimeout(() => {
callback(null, "Async returned data");
}, 100);
}
function findData( param ) {
const currentFiber = Fiber.current;
var response = null;
findDataAsync(param, function (err, data) {
response = { err : err, data : data };
currentFiber.run();
});
Fiber.yield();
if (response.err) {
throw response.err;
} else {
return response.data;
}
}
function main() {
console.log("Inside fiber started");
console.log(findData());
console.log("Inside fiber finished");
}
console.log("Outside fiber started");
Fiber(main).run();
console.log("Outside fiber finished");
This should output:
Outside fiber started
Inside fiber started
Outside fiber finished
Async returned data
Inside fiber finished
Notice that Outside fiber finished
is logged immediately after the first yield in the fiber is called.
As you see, we had to start a fiber immediately to be able to yield
. If you try to use fibers in a third party library, you have to make sure that the library does not "reset" your current execution context to the javascript event loop by calling setTimeout
or issuing asynchronous http requests.