transpiler battle: breaking out of nested function, with vs without throw - javascript

I have just finished writing "version 0" of my first (toy) transpiler. It works. It turns a string of "pseudo JavaScript" (JavaScript with an additional feature) into a string of runnable JavaScript. Now, I want to improve it.
The work area possibly most interesting for other SO users is this: The compiled code (i.e., output of my transpiler) does not heed a coding style recommendation as given in an accepted answer to some earlier SO question. If I would have at my hands a second transpiler where that coding style recommendation is heeded, I could make an informed decision regarding which branch is more promising to continue to develop on - I'd like to compare the 2 braches regarding performance, development time needed, amount of bugs, and so on, and decide based on that.
Let me tell you about the "additional JS feature" my transpiler deals with: "nested return". Consider closures / nested functions like so
function myOuterFunc(){
... code ...
function innerFunc(){
... code ...
}
... code ...
}
(note that above '...code...' is supposed to include every possible JS code including more nested function declarations, so myOuterFunc is not necessarily the direct parent of innerFunc)
In above situation, suppose you desire to return a result from myOuterFunc from somewhere inside - not necessarily directly inside - innerFunc
With "nested return" implemented, you could then write simply
return.myOuterFunc result
Here is an exmalpe of a (not-runnable) function using this feature and doing something meaningful
function multiDimensionalFind(isNeedle, haystack) {
// haystack is an array of arrays
// loop (recursively) through all ways of picking one element from each array in haystack
// feed the picked elements as array to isNeedle and return immediately when isNeedle gives true
// with those picked elements being the result, i.e. the 'found needle'
var LEVEL = haystack.length;
function inner(stack) {
var level = stack.length;
if (level >= LEVEL) {
if (isNeedle(stack)) return.multiDimensionalFind stack;
} else {
var arr = haystack[level];
for (var i = 0; i < arr.length; i++) {
inner(stack.concat([arr[i]]));
}
}
}
inner([]);
return 'not found'
}
And here is the (runnable) code my transpiler automatically produces from that (comments were added/remove later, obviously), followed by some code testing if that function does what it claims to do (and it does, as you can convince yourself.)
///////////// the function /////////////////
function multiDimensionalFind(isNeedle, haystack) {
try {
var LEVEL = haystack.length;
function inner(stack) {
var level = stack.length;
if (level >= LEVEL) {
if (isNeedle(stack)) throw stack;
} else {
var arr = haystack[level];
for (var i = 0; i < arr.length; i++) {
inner(stack.concat([arr[i]]));
}
}
}
inner([]);
return 'not found'
} catch(e){
// make sure "genuine" errors don't get destroyed or mishandled
if (e instanceof Error) throw e; else return e;
}
}
////////////////// test it //////////////////
content = document.getElementById('content');
function log2console(){
var digits = [0,1];
var haystack = [digits,digits,digits,digits,digits];
var str = '';
function isNeedle(stack){
str = str + ', ' + stack.join('')
return false;
}
multiDimensionalFind(isNeedle, haystack);
content.textContent = str;
}
function find71529(){ // second button
var digits = [0,1,2,3,4,5,6,7,8,9]
var haystack = [digits,digits,digits,digits,digits]
function isNeedle(stack){
return stack.reduce(function(b,i){ return 10*b+i; }, 0) === 71529
// returns true iff the stack contains [7,1,5,2,9]
}
content.textContent = multiDimensionalFind(
isNeedle, haystack
).join('_')
}
<button onclick='log2console()'>print binary numbers with 5 digits</button>
<br>
<button onclick='find71529()'>find something is 5d space</button>
<div id='content'></div>
You can play around with my transpiler in this fiddle here. I'm using the esprima library, the escodegen.js library on top of esprima, a teeny tiny work in progress abstract syntax tree generation library of my own (see the script tags in the fiddle). The code which is not library, and not UI code, i.e. the "real meat" of the transpiler has less than 100 lines (see function transpile). So this might be a lot less complicated than you thought.
I can't remember where I had seen the style recommendation, but I am certain that it was actually in multiple places. If you know or come across one such question, I invite you to be so kind to put the link into a comment under the question, I will mark useful. So far, there is one link, thank you Barmar.
You might ask why I even bothered to write a "non-compliant" transpiler first, and did not go for the "compliant" version straight away. That has to do with the estimated amount of work. I estimate the amount of work to be much larger for the "compliant" version. So much so, that it didn't really seem worthwhile to embark on such an endeavor. I would very much like to know whether this assessment of the amount of work is correct or incorrect. Thus the question. Please do not insinuate a rhetorical, or even a dishonest motive for the question; however weird it might sound to some, it really is the case that I'd like to be proven wrong, so please be so kind not to assume I'm "just saying that" for whatever reason, you'd be doing me an injustice. This is, of all the questions I asked on SO so far, by far the one I've put the most work into. And, if you ask me, it is by far the best question I have ever asked here.
Apart from someone assisting me in writing the "compliant" version of the transpiler, I'm also interested (albeit to a lesser degree) in anything objectively demonstrable which stands a chance to convince me that the "non-compliant" way is the wrong way. Speed tests (with links to jsperf), reproducible bug reports, things of that sort.
I should mention the speed tests I have done myself so far:
first test, second test
loosely related question

The better way really is to use return (if you can't completely refactor the tower). It makes it clear what you're doing and when you're returning a value from the intermediate functions; you can tell by looking at those functions where the result may be provided. In contrast, using throw is invisible in those intermediate layers; it magically bypassing them in a way designed for error conditions.
If you don't want to do that, I don't think you have a reasonable alternative other than throw. I wondered about going down the route of generator functions or similar, but I think that would just complicate things more, not less.
Using return doesn't markedly complicate the example code, and does (to my eye) make it clearer what's going on and when results are potentially expected.
function wrapper(){
function first(){
function second(){
function third(){
doStuff4();
some loop {
var result = ...
if (something) return result;
}
}
doStuff2();
let result = third();
if (result) {
return result;
}
doStuff3();
return third();
}
doStuff1();
return second();
}
return first() || "not found";
}
(In the above, result is tested for truthiness; substitute something else if appropriate.)

Ok, here is another approach with use of all async power of JavaScript... So basically I've recreated your nested functions but with use of Promise/await technique. You will get result only once, the first time you'll resolve it from any level of nested functions. Everything else will be GC. Check it out:
// Create async function
(async () => {
const fnStack = (val) => {
return new Promise((resolve, reject) => {
// Worker functions.
// Could be async!
const doStuff1 = (val) => val + 1;
const doStuff2 = (val) => val * 2;
const doStuff3 = (val) => val * -1; // This will not affect result
const doStuff4 = (val) => val + 1000;
// Nested hell
function first() {
function second() {
function third() {
val = doStuff4(val);
// Some loop
for(let i = 0; i < 1000; i++) {
if(i === 500) {
// Here we got our result
// Resolve it!
resolve(val);
}
}
}
val = doStuff2(val);
third();
// Below code will not affect
// resolved result in third() above
val = doStuff3(val);
third();
}
val = doStuff1(val);
second();
}
//
first();
});
}
// Run and get value
const val = await fnStack(5);
// We get our result ones
console.log(val);
})();

I think you should use arrays;
const funcs = [first, second, third];
for(let i = 0; i < funcs.length; ++i){
const result = funcs[i]();
if (result) break;
}
You should return only from function that has the result.

Sometime later, when I get around to it, I'll add instructions here on how to use my abstract syntax tree generation library which I used for my transpiler, maybe even start a little towards the other version, maybe explaining in more detail what the things are which make me think that it is more work.
old version follows (will be deleted soon)
If the feature is used multiple times we'll need something like this:
function NestedThrowee(funcName, value){
this.funcName = funcName;
this.value = value;
}
return.someFunctionName someReturnValue (before compilation) will give (after compliation) something like
var toBeThrown = new NestedThrowee("someFunctionName", someReturnValue);
And inside the generated catch block
if (e instanceof Error){
throw e; // re-throw "genuine" Error
} else {
if (e instance of NestedThrowee){
if (e.funcName === ... the name of the function to which
this catch block here belongs ...) return e.value;
throw new Error('something happened which mathheadinclouds deemed impossible');
}
In the general case, it is necessary to wrap the result (or 'throwee') like shown above, because there could be multiple, possibly nested "nested returns", and we have to take care that the catch phrase and caught object of type NestedThrowee match (by function name).

Related

How would I perform variable capture in a higher order javascript function?

hullo all,
jslint is mad at me.
i'm making a function within a loop, but i'm also not quite sure how to fix it, since it seems i would need to curry the result such that the function matches the signature expected by request for a callback as well as perform variable capture correctly or perform some other javascript devilry to simplify that.
edit: the code as it is works fine. i'd just like to know how to make it so the linter isn't made at me anymore!
the section of code looks like the following:
function func(cb) {
request({ params }, (error, response) => {
const devices = response.body;
let completedCounter = 0;
for (const device of devices) {
request({ params }, (err, response) => {
if (!err && response.statusCode === 200) {
completedCounter += 1;
if (completedCounter === devices.length) {
cb(null, "message here");
}
} else {
cb(err, "message here");
}
});
}
});
}
sorry if my terminology isn't typical javascript terminology- i'm a confused c++/python/lisp programmer outside his comfort zone!
the linter output is:
39:10 error Don't make functions within a loop no-loop-func
I'm not exactly sure what you're trying to do in the code, as there are parts missing (or parts that are gratuitous, which I've commented or stubbed out, below), but this lints in the most recent version of JSLint.
/*jslint node, es6, for, white */
var request = require("request");
function func(cb) {
"use strict";
var params = {};
// See https://plus.google.com/108103301822680819489/posts/ZWBUMhYGcrH
request(params, function (ignore, response) {
const devices = response.body;
var completedCounter = 0;
Object.keys(devices).forEach(function(/*k*/) {
// var device = devices[k]; // `device` is unused, so we need neither it nor `k`, above
var params2 = {};
request(params2, function (err, response2) {
if (!err && response2.statusCode === 200) {
completedCounter += 1;
if (completedCounter === devices.length) {
cb(null, "message here");
}
} else {
cb(err, "message here");
}
});
});
});
}
func(); // Needs to be used or exported somehow.
Farts/Arrow Notation in JSLint
JSLint does want a "fart" (arrow notation) to return in a single line. Otherwise, JSLint prefers you use function ( notation to make what you're doing more clear.
Check the discussion here, at the JSLint discussion group. Crockford demonstrates what I suggest, above, and then Lee Chase adds...
Arrow functions have a problem with { }, mainly is it a multiline
function or an object.
As it happens your function returns nothing as multiline arrow
functions need a return.
That makes some sense. And the OP at that link makes precisely the mistake JSLint is trying to help you avoid. That is, the stylistic error did in fact (in that case) cause a functional one.
Your "function in a loop" issue
Using forEach with Object.keys, another set of JSLint recommendations (Object.keys and for) helps eliminate the overhead of redeclaring functions as well. You don't, as a rule, want to use for (x in y).
Though why JSLint does not consider for... of to be a "good part" of ES6, I don't know.

Javascript Scope Issues for inner-function

Pretty sure this has been asked already, but I don't know what to search for. Anyway,
var livemarks = [];
var livemarkIds = PlacesUtils.annotations.getItemsWithAnnotation("livemark/feedURI", {});
for (var i = 0; i < livemarkIds.length; i++){
PlacesUtils.livemarks.getLivemark( {id : livemarkIds[i]}, function(result, livemark){
if (result == Components.results.NS_OK){
livemarks.push(livemark);
}
});
}
alert(livemarks.length);
I am trying to play a bit with a Firefox addon that's no longer maintained by its creator, just to learn a bit. I recently got an error saying getFeedURI is going to be deprecated and I want to change his old function.
EDIT:
From a function defined in a function (inner function), I am unable to access a var defined in the parent. Why?
E.g. I cannot access var livemarks from inside getLivemark(), or other similar internal functions.
I was checking (scroll down completely): this and his code works fine. So what's wrong with my code? I just wanted to avoid the recursion, if possible.
I suspect the PlacesUtils.livemarks.getLivemark function does its work asynchronously, so your callback is called after you alert the length. Put your alert inside the callback and you should see the correct length (eventually). Here's one way:
var expecting = livemarkIds.length;
for (var i = 0; i < livemarkIds.length; i++){
PlacesUtils.livemarks.getLivemark( {id : livemarkIds[i]}, function(result, livemark){
if (result == Components.results.NS_OK){
livemarks.push(livemark);
// ***New stuff***
if (livemarks.length === expecting) {
// Now you have them all, now you can do the next thing
doSomethingWithTheLiveMarks(livemarks);
}
}
});
}
Note that there I put livemarkIds.length into expecting, just in case you do other things with livemarkIds while the function is running. If you aren't, you can just use that directly.
Re your comment below:
However, the system works like this: I get the livemarks in an array. This code is in a class (and method) actually, so another class initializes this one and will call the function getFeeds(), which will return that array of livemarks.
If PlacesUtils.livemarks.getLivemark is asynchronous, it's impossible for getFeeds to return the array as a return value. E.g., it cannot be used like this:
a = b;
c = 42;
feeds = getFeeds(feedIds);
if (feeds.length === 0) {
// Do something
}
else {
// Do something else
}
The good news is it's really easy to fix: Have getFeeds accept a callback function that it calls when it has the feeds. The code above changes to look like this:
a = b;
c = 42;
feeds = getFeeds(feedIds, function(feeds) {
if (feeds.length === 0) {
// Do something
}
else {
// Do something else
}
});
As you can see, it's a pretty straightforward change. Assuming the loop above is all of getFeeds, then getFeeds ends up looking something like this:
function getFeeds(livemarkIds, callback) {
var livemarks = [];
for (var i = 0; i < livemarkIds.length; i++){
PlacesUtils.livemarks.getLivemark( {id : livemarkIds[i]}, function(result, livemark){
if (result == Components.results.NS_OK){
livemarks.push(livemark);
if (livemarks.length === livemarkIds.length) {
// Done, trigger the callback
callback(livemarks);
}
}
});
}
}
And the pattern continues: If the code calling getFeeds is being called by something else that's expecting a return value from the async stuff, instead of returning that value, you have that code accept a callback, and call the callback from the getFeeds callback. And so on.
Once you get used to it, it's very easy to do. Getting used to it can be tricky. :-)

What's the cleanest way to write a non-blocking for loop in javascript?

So, I've been thinking about a brain teaser - what if I had a large object I for some reason had to iterate through in node js, and didn't want to block the event loop while I was doing that?
Here's an off-the-top-of-my-head example, I'm sure it can be much cleaner:
var forin = function(obj,callback){
var keys = Object.keys(obj),
index = 0,
interval = setInterval(function(){
if(index < keys.length){
callback(keys[index],obj[keys[index]],obj);
} else {
clearInterval(interval);
}
index ++;
},0);
}
While I'm sure there are other reasons for it being messy, this will execute slower than a regular for loop, because setInterval 0 doesn't actually execute every 0 ms, but I'm not sure how to make a loop with the much faster process.nextTick.
In my tests, I found this example takes 7 ms to run, as opposed to a native for loop (with hasOwnProperty() checks, logging the same info), which takes 4 ms.
So, what's the cleanest/fastest way to write this same code using node.js?
The behavior of process.nextTick has changed since the question was asked. The previous answers also did not follow the question as per the cleanliness and efficiency of the function.
// in node 0.9.0, process.nextTick fired before IO events, but setImmediate did
// not yet exist. before 0.9.0, process.nextTick between IO events, and after
// 0.9.0 it fired before IO events. if setImmediate and process.nextTick are
// both missing fall back to the tick shim.
var tick =
(root.process && process.versions && process.versions.node === '0.9.0') ?
tickShim :
(root.setImmediate || (root.process && process.nextTick) || tickShim);
function tickShim(fn) {setTimeout(fn, 1);}
// executes the iter function for the first object key immediately, can be
// tweaked to instead defer immediately
function asyncForEach(object, iter) {
var keys = Object.keys(object), offset = 0;
(function next() {
// invoke the iterator function
iter.call(object, keys[offset], object[keys[offset]], object);
if (++offset < keys.length) {
tick(next);
}
})();
}
Do take note of #alessioalex's comments regarding Kue and proper job queueing.
See also: share-time, a module I wrote to do something similar to the intent of the original question.
There are many things to be said here.
If you have a web application for example, you wouldn't want to do "heavy lifting" in that application's process. Even though your algorithm is efficient, it would still most probably slow down the app.
Depending on what you're trying to achieve, you would probably use one of the following approaches:
a) put your "for in" loop in a child process and get the result in your main app once it's over
b) if you are trying to achieve something like delayed jobs (for ex sending emails) you should try https://github.com/LearnBoost/kue
c) make a Kue-like program of your own using Redis to communicate between the main app and the "heavy lifting" app.
For these approaches you could also use multiple processes (for concurrency).
Now time for a sample code (it may not be perfect, so if you have a better suggestion please correct me):
var forIn, obj;
// the "for in" loop
forIn = function(obj, callback){
var keys = Object.keys(obj);
(function iterate(keys) {
process.nextTick(function () {
callback(keys[0], obj[keys[0]]);
return ((keys = keys.slice(1)).length && iterate(keys));
});
})(keys);
};
// example usage of forIn
// console.log the key-val pair in the callback
function start_processing_the_big_object(my_object) {
forIn(my_object, function (key, val) { console.log("key: %s; val: %s;", key, val); });
}
// Let's simulate a big object here
// and call the function above once the object is created
obj = {};
(function test(obj, i) {
obj[i--] = "blah_blah_" + i;
if (!i) { start_processing_the_big_object(obj); }
return (i && process.nextTick(function() { test(obj, i); }));
})(obj, 30000);
Instead of:
for (var i=0; i<len; i++) {
doSomething(i);
}
do something like this:
var i = 0, limit;
while (i < len) {
limit = (i+100);
if (limit > len)
limit = len;
process.nextTick(function(){
for (; i<limit; i++) {
doSomething(i);
}
});
}
}
This will run 100 iterations of the loop, then return control to the system for a moment, then pick up where it left off, till its done.
Edit: here it is adapted for your particular case (and with the number of iterations it performs at a time passed in as an argument):
var forin = function(obj, callback, numPerChunk){
var keys = Object.keys(obj);
var len = keys.length;
var i = 0, limit;
while (i < len) {
limit = i + numPerChunk;
if (limit > len)
limit = len;
process.nextTick(function(){
for (; i<limit; i++) {
callback(keys[i], obj[keys[i]], obj);
}
});
}
}
The following applies to [browser] JavaScript; it may be entirely irrelevant to node.js.
Two options I know of:
Use multiple timers to process the queue. They will interleave which will give the net effect of "processing items more often" (this is also a good way to steal more CPU ;-), or,
Do more work per cycle, either count or time based.
I am not sure if Web Workers are applicable/available.
Happy coding.

Resolve two anonymous functions to the same definition point?

I have code in the following form in which the user may specify a callback which will be called at a later time:
var _deferred = [];
var deferred = function(callback) {
_deferred.push(callback);
}
var doDeferred = function() {
for(var i = 0, max = _deferred.length; i < max; i++) {
_deferred[i].call();
}
}
for(var i = 0; i < 5; i++) {
deferred(function() {
console.log("Some deferred stuff");
});
}
doDeferred();
I would like to recognize that the callback specified to deferred() is an anonymous function resolving to the same origin, and only allow it to be added once. Aka in the bottom for loop it would throw an exception when i = 1.
Like:
var deferred = function(callback) {
if(_deferred.indexOf(callback) !== -1) {
throw "Already added!";
}
_deferred.push(callback);
}
I can think of many ways of doing this by adding a "key", but I'm wondering if I can use something along the lines of Function.caller to create a "source hash"?
Is there a solution for this out there already that I'm not seeing? I'd really prefer to accept this burden onto myself rather than push it out to the caller of deferred and have them provide some sort of unique id.
EDIT:
To clarify any confusion.
Yes each call to deferred is with a unique function object, has its own closure, etc. Therefore my indexOf will always fail. That is not a point of confusion.
The question is that these anonymous functions are declared in the same place, they are the same code, how can I determine that? I'm looking to determine declarative equality, not instance equality. I was thinking I could somehow create a hash based on caller of deferred...
CONCLUSION:
Thanks guys, it seems like there is no really elegant solution here. The toString method is not definitive (different functions with same body will test equally as strings) - and is just ugly. I'm going to put the burden on the caller.
The thing is, in the loop at the bottom, they are different functions, so in all fairness they should both be included (and honestly, there is no guarantee that the values from both functions won't be different depending on the variables present at the moment). I'm also not sure that 'unique functions only' is something which people expect, so it might cause a good deal of "debugging"
This isn't something which is required of ECMAScript, but Function.toString() will generally return its internal structure. So you probably want:
var ids = [] // separate ID takes up slightly more space, but lookup should
// be faster.
var deferred = function(callback) {
var cbs = callback.toString() // or String(callback)
if(ids.indexOf( cbs ) !== -1)
{
throw "Already added!";
}
ids.push( cbs )
_deferred.push(callback);
}
If you're willing to use a for... in loop:
var _deferred = {}
var deferred = function(callback) {
var cbs = callback.toString() // or String(callback)
if( _deferred[ cbs] )
{
throw "Already added!";
}
_deferred[ cbs] = callback;
}
// caution, this executes in arbitrary order.
var doDeferred = function() {
for(var i in _deferred) {
_deferred[i].call();
}
}
As far as I know, if you have two anonymous functions with the same bodies, they will not be equivalent in terms of the "==" operator, so I don't think you can do the indexOf().
You could check if your new function has the same body as any function already in your array. To do this just convert the function to a string and check for equality:
String((function(){/*something*/})) == String((function(){/*something*/}))
Should return true;
var deferred = function(callback) {
if(_deferred.some(function(c){return c.toString() === callback.toString()})) {
throw "Already added!";
}
_deferred.push(callback);
}
This will throw the error the first time a duplicate method signature is added.
Though I wouldn't consider this elegant, you can compare anonymous functions by using their toString() method.
var deferred = function(callback) {
var str = callback.toString();
for var i = 0; i < _deferred.length; i++) {
if (_deferred[i].toString() == str) {
throw "Already added!";
}
}
_deferred.push(callback);
}

How to simulate JavaScript yield?

One of the new mechanisms available in JavaScript 1.7 is yield, useful for generators and iterators.
This is currently supported in Mozilla browsers only (that I'm aware of). What are some of the ways to simulate this behavior in browsers where it is not available?
Well you could always write an outer function that initializes variables in a closure and then returns an object that does whatever work you want.
function fakeGenerator(x) {
var i = 0;
return {
next: function() {
return i < x ? (i += 1) : x;
}
};
}
Now you can write:
var gen = fakeGenerator(10);
and then call gen.next() over and over again. It'd be tricky to simulate the "finally" behavior of the "close()" method on real generators, but you might be able to get somewhere close.
Similar to Pointy's answer, but with a hasNext method:
MyList.prototype.iterator = function() { //MyList is the class you want to add an iterator to
var index=0;
var thisRef = this;
return {
hasNext: function() {
return index < thisRef._internalList.length;
},
next: function() {
return thisRef._internalList[index++];
}
};
};
The hasNext method let's you loop like:
var iter = myList.iterator() //myList is a populated instance of MyList
while (iter.hasNext())
{
var current = iter.next();
//do something with current
}
For a non-trivial generator function, you will want to use some sort of tool to translate your code to an ES3 equivalent so that it can run in any modern browser. I recommend trying out Traceur, which can roughly be described as an ES6-to-ES3 source translator. Because generators are a language feature destined for ES6, Traceur will be able to translate them for you.
Traceur provides a demo page where you can type ES6 code and see the ES3 generated on the fly. If you enter something as simple as:
// Note that this declaration includes an asterisk, as specified by current ES6
// proposals. As of version 16, Firefox's built-in support for generator
// functions does not allow the asterisk.
function* foo() {
var n = 0;
if (n < 10) {
n++;
yield n;
}
}
for (var n of foo()) {
console.log(n);
}
you will see that the equivalent ES3 code is non-trivial, and it requires traceur.runtime to be included so that the code runs correctly in a browser. The runtime is defined in http://traceur-compiler.googlecode.com/git/src/runtime/runtime.js, which is currently 14K (unminified). This is a non-trivial amount of code, though likely much of it can be optimized away using the Closure Compiler.
Note there is also a bug filed to provide an option to inline the required functions from the traceur.runtime namespace, which would eliminate the need to include runtime.js altogether: https://code.google.com/p/traceur-compiler/issues/detail?id=119.
Without some sort of compiler or preprocessor… No.
The closest you can come is something like this:
function doStuff() {
var result = { };
function firstStuf() { ...; result.next = secondStuff; return 42; };
function secondStuf() { ...; result.next = thirdStuff; return 16; };
function thirdStuf() { ...; result.next = null; return 7; };
result.next = firstStuff;
return result;
}
But, well… That's pretty crappy, and really isn't much of a substitute.
I have started a little project that tries to do this with some callback trickery. Since it's impossible to create real coroutines in "standard" JavaScript, this doesn't come without a few caveats, e.g:
it's impossible to make this follow the iterator protocol (stuff like .next() etc.),
it's impossible to iterate through several generators at once,
you have to watch out not to let the wrong objects leave the generator's scope (e.g. by calling yield in a timeout – since this is "plain" JavaScript, there's no syntax restriction that prevents you from doing this),
exceptions in the generator are a little tricky,
and last not least, it's very experimental (just started this a few days ago).
On the bright side, you have yield! :)
The Fibonacci example from the MDC page would look like this:
var fibonacci = Generator(function () {
var fn1 = 1;
var fn2 = 1;
while (1){
var current = fn2;
fn2 = fn1;
fn1 = fn1 + current;
this.yield(current);
}
});
console.log(fibonacci.take(10).toArray());
Output:
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
The project is on BitBucket at https://bitbucket.org/balpha/lyfe.

Categories

Resources