Giter VIP home page Giter VIP logo

continuation's Introduction

Continuation.js

This project has been deprecated and discontinued. Please stop using it and migrate to ES7 async and await.

Overview

Continuation.js is a compiler for Continuation-Passing Style transformation, which simplifies asynchronous JavaScript programming. It translates slightly flavored JavaScript syntax into standard JavaScript, so it can be also called a "translator". Continuation.js introduces a virtual function cont, which allow you to write continuation-passing style code (or asynchronous callback style code) far easier. cont is not a actual function, but a mark with the same syntax to function calls in JavaScript. By using Continuation.js you can write asynchronous control flows like flat threaded code, and it compiles it into continuation-passing style code.

Typically, writing with asynchronous control flow is a pain, because you will easily write nested callbacks like below:

function textProcessing(callback) {
  fs.readFile('somefile.txt', 'utf-8', function (err, contents) {
    if (err) return callback(err);
    //process contents
    contents = contents.toUpperCase();
    fs.readFile('somefile2.txt', 'utf-8', function (err, contents2) {
      if (err) return callback(err);
      contents += contents2;
      fs.writeFile('somefile_concat_uppercase.txt', contents, function (err) {
        if (err) return callback(err);
        callback(null, contents);
      });
    });
  });
}
textProcessing(function (err, contents) {
  if (err)
    console.error(err);
});

This kind of coding style is called "callback hells" or "callback pyramids". While using Continuation.js, you directly write:

function textProcessing(ret) {
  fs.readFile('somefile.txt', 'utf-8', cont(err, contents));
  if (err) return ret(err);
  contents = contents.toUpperCase();
  fs.readFile('somefile2.txt', 'utf-8', cont(err, contents2));
  if (err) return ret(err);
  contents += contents2;
  fs.writeFile('somefile_concat_uppercase.txt', contents, cont(err));
  if (err) return ret(err);
  ret(null, contents);
}
textProcessing(cont(err, contents));
if (err)
  console.error(err);

The code above is flatted by using the virtual function cont. Control flow must "wait" for the return of asynchronous function call fs.readFile. Parameters in the argument list of cont will be set after it returns. "Return" here is a little confusing because in an asynchronous function "return" means callback function called, not "return" in the literal sense. An asynchronous function usually returns immediately (by encountering return statement or the end of the function scope) while the callback function could be called later. You can be understood as all the statements after cont until the end of the function are the callback function of the asynchronous function call. The code feels like threaded code, but it is still asynchronous while executing.

Even more simply, the asynchronous error can be held with JavaScript try...catch syntax and another virtual function call obtain provided by Continuation.js. obtain(a) is equivalent to cont(err, a), and err would be thrown if it is not undefined.

function textProcessing(ret) {
  try {
    fs.readFile('somefile.txt', 'utf-8', obtain(contents));
    contents = contents.toUpperCase();
    fs.readFile('somefile2.txt', 'utf-8', obtain(contents2));
    contents += contents2;
    fs.writeFile('somefile_concat_uppercase.txt', contents, obtain());
    ret(null, contents);
  } catch(err) {
    ret(err);
  }
}
try {
  textProcessing(obtain(contents));
} catch(err) {
  console.error(err);
}

Features

  • A JIT (Just-in-time compilation) and AOT (Ahead-of-time) compiler
  • Strictly no runtime dependence
  • No additional non-native JavaScript syntax and very few reserved keywords (only cont, obtain and parallel, also they can be renamed by aliasing)
  • Flexible coding style and readable compiled code
  • Compatible with CoffeeScript and LiveScript (and other compile-to-js language)
  • Supports both Node.js and browser-side JavaScript
  • Supports execution in parallel and lightweight thread

Documentation

cont

cont is a mark of asynchronous calls. It must be used in the place of callback function parameter of a function call. The parameters in cont will be set to the values of arguments of the callback function. If parameter of cont is a variable (not an expression), it will be defined automatically before the function call.

Example:

setTimeout(cont(), 1000);

fs.lstat('/path/file', cont(err, stats));

var obj;
fs.readdir('/path', cont(err, obj.files));

Compiled code:

var err, stats, obj;
setTimeout(function () {
  fs.lstat('/path/file', function () {
    err = arguments[0];
    stats = arguments[1];
    fs.readdir('/path', function () {
      err = arguments[0];
      obj.files = arguments[1];
    });
  });
}, 1000);

obtain

obtain is a syntax sugar of cont and throw. You can use try to catch asynchronous errors with obtain. One assumption is that the error object is the first parameter of the callback function (this is a convention of Node.js API).

Example:

function f1() {
  fs.readdir('/path', obtain(files));
}

function f2() {
  fs.readdir('/path', cont(err, files));
  if (err)
    throw err;
}

Compiled code:

function f1() {
  var _$err, files;
  fs.readdir('/path', function () {
    _$err = arguments[0];
    files = arguments[1];
    if (_$err)
      throw _$err;
  });
}
function f2() {
  var err, files;
  fs.readdir('/path', function () {
    err = arguments[0];
    files = arguments[1];
    if (err) {
      throw err;
    }
  });
}

parallel

parallel allows you to execute asynchronous functions "in parallel". parallel is also a virtual function and its parameters should be all function calls with cont or obtain. All function calls in parallel will be executed in parallel and control flow continues executing the next statement after all the parallel function calls "return" (precisely speaking callback functions called).

Note that both Node.js and browser execute JavaScript code in single thread, so this is not a multithreaded implementation. The function calls feel like entrances of threads so they can be called "lightweight threads". Only I/O and computing are executed in parallel while computing are actually executed in sequence. That is, when one "thread" is "blocked" by I/O, the other one runs. The "threads" can automatically utilize the gaps of I/O and computing. So you should let functions that both have I/O and computing run in parallel, rather than all functions with heavy computing and little I/O.

Example:

var contents = {};
parallel(
  fs.readFile('/path1', obtain(contents.file1)),
  fs.readFile('/path2', obtain(contents.file2)),
  fs.readFile('/path3', obtain(contents.file3))
);
console.log(contents);

Explicit mode

Modules can be written in Continuation.js and they will be recursively compiled automatically when using require. Add 'use continuation' into your source file, and use continuation script.js --explicit to run it and only files contains 'use continuation' will be compiled. This option can reduce loading time if many modules are recursively required.

Compilation cache

By using contination script.js --cache [cacheDir], all modules compiled by Contination.js will be cached into cacheDir. If the timestamp of your source file is newer than the cached version, it will be compiled again. This option rely on the system clock and it can also reduce loading time. It is recommended to use --explicit and --cache together.

By default cacheDir is /tmp/continuation.

Use Continuation.js in CoffeeScript (and other compile-to-js language)

Continuation.js is compatible with most kinds of compile-to-js language because it introduces no non-primitive syntax. The only 3 keywords cont, obtain and parallel are all virtual functions so you can use function call directly in your language.

Example (CoffeeScript):

dns = require('dns')
domains = ['www.google.com', 'nodejs.org', 'www.byvoid.com']
for domain in domains
  dns.resolve domain, obtain(addresses)
  console.log addresses

Until now CoffeeScript and LiveScript are supported by default.

Use Continuation.js programmatically

You are able to use Continuation.js programmatically. Continuation.js module has one interface function compile(code). code must be a string.

Example:

var continuation = require('continuation');

function fibonacci() {
  var a = 0, current = 1;
  while (true) {
    var b = a;
    a = current;
    current = a + b;
    setTimeout(cont(), 1000);
    console.log(current);
  }
};

var code = fibonacci.toString();
var compiledCode = continuation.compile(code);
console.log(compiledCode);
eval(compiledCode);
fibonacci();

You can run the code above using node command. That means you don't have to install Continuation.js in global environment. The code above converts a function into a string, and then it is compiled by Continuation.js. After that you can run it via eval function.

Usage

Usage: continuation [options] <file.js/file.coffee/file.ls> [arguments]

Options:

  -h, --help               output usage information
  -V, --version            output the version number
  -p, --print              compile script file and print it
  -o, --output <filename>  compile script file and save as <filename>
  -e, --explicit           compile only if "use continuation" is explicitly declared
  -c, --cache [directory]  run and cache compiled sources to [directory], by default [directory] is /tmp/continuation
  -v, --verbose            print verbosal information to stderr
  --alias-cont <aliasCont>          set another name for "cont" function
  --alias-obtain <aliasObtain>      set another name for "obtain" function
  --alias-parallel <aliasParallel>  set another name for "parallel" function

Run code written with Continuation.js (i.e. script.js):

contination script.js

Print compiled code on console:

contination script.js -p

Compile code and save as another file:

contination script.js -o compiled.js

Run code in "explicit mode" (only compile sources with 'use continuation'. see documentation):

contination script.js -e

Cache compiled code (including recursively required modules) to accelerate loading (see documentation):

contination script.js -c

Change names of built-in functions:

contination script.js --alias-cont cb --alias-obtain tryCb --alias-parallel par

Examples

Loops and sleep

Calculating Fibonacci sequence and printing one number by every one second:

var fib = function () {
  var a = 0, current = 1;
  while (true) {
    var b = a;
    a = current;
    current = a + b;
    setTimeout(cont(), 1000);
    console.log(current);
  }
};
fib();

Run asynchronous functions in sequence

Read 5 files in sequence:

var fs = require('fs');

for (var i = 0; i < 4; i++) {
  fs.readFile('text' + i + '.js', 'utf-8', obtain(text));
  console.log(text);
}

console.log('Done');

Run asynchronous functions in parallel

Do things (with heave I/O) in parallel:

var fs = require('fs');
var dns = require('dns');
var http = require('http');

var complexWork = function (next) {
  setTimeout(cont(), 500);
  http.get('http://www.byvoid.com', cont(res));
  next(null, res.headers);
};

parallel(
  fs.readdir('/', obtain(files)),
  dns.resolve('npmjs.org', obtain(addresses)),
  complexWork(obtain(result))
);

console.log(files, addresses, result);

Recursions

Calculating disk usage:

var fs = require('fs');

function calcDirSize(path, callback) {
  var dirSize = 0, dirBlockSize = 0;
  fs.readdir(path, obtain(files));
  for (var i = 0; i < files.length; i++) {
    var filename = path + '/' + files[i];
    fs.lstat(filename, obtain(stats));
    if (stats.isDirectory()) {
      calcDirSize(filename, obtain(subDirSize, subDirBlockSize));
      dirSize += subDirSize;
      dirBlockSize += subDirBlockSize;
    } else {
      dirSize += stats.size;
      dirBlockSize += 512 * stats.blocks;
    }
  }
  callback(null, dirSize, dirBlockSize);
}

var path = process.argv[2];
if (!path) path = '.';

calcDirSize(path, obtain(totalSize, totalBlockSize));

console.log('Size:', Math.round(totalSize / 1024), 'KB');
console.log('Actual Size on Disk:', Math.round(totalBlockSize / 1024), 'KB');

More examples are available in 'examples' directory and 'test' directory.

Relevant projects

Continuation.js is not the only solution of CPS transformation, there are some alternatives. Below is a comparison among projects related to synchronous to asynchronous transformation.

Project Continuation.js streamline.js TameJS Wind.js jwacs NarrativeJS StratifiedJS
Node.js support Yes Yes Yes Yes No No Yes
Browser side support Yes Yes No Yes Yes Yes Yes
Additional runtime dependence No Yes Yes Yes No Yes Yes
Additional syntax No No Yes No Yes Yes Yes
Compatibility with compile-to-js language Yes Yes (CoffeeScript) Yes (CoffeeScript) Yes (manually) No No No
Parallel support Yes Yes Yes Yes Yes Unknown Yes
Readable generated code Yes No Hardly Almost Unknown No Unknown
Asynchronous results passing syntax Parameters Return value Parameters Return value Return value Return value Return value
Documentation Yes Yes Yes No Yes Yes Yes
Implemented in JavaScript JavaScript JavaScript JavaScript Lisp Java JavaScript

Contributers

continuation's People

Contributors

alhimik45 avatar byvoid avatar curimit avatar pimterry avatar reynir avatar shankerwangmiao avatar summivox avatar tomibelan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

continuation's Issues

Compiled code can't get the correct return value

When mix using obtain and return in one function, it seems it can't work properly.
For an example code like

'use continuation'
getElement = (callback) ->
  callback null, 1

checkElement = (number) ->
  getElement obtain standard
  number is standard

console.log checkElement 1
console.log checkElement 2

Which is aimed to check if an element is 1

After just

$ coffee -c a.coffee 

it produce

// Generated by CoffeeScript 1.6.2
(function() {
  'use continuation';
  var checkElement, getElement;

  getElement = function(callback) {
    return callback(null, 1);
  };

  checkElement = function(number) {
    getElement(obtain(standard));
    return number === standard;
  };

  console.log(checkElement(1));

  console.log(checkElement(2));

}).call(this);

The code seems shall work though. However, after using

$ continuation a.coffee -o abc.js

It produce

(function () {
  var checkElement, getElement;
  'use continuation';
  getElement = function (callback) {
    return callback(null, 1);
  };
  checkElement = function (number) {
    var _$err, standard;
    getElement(function () {
      _$err = arguments[0];
      standard = arguments[1];
      if (_$err)
        throw _$err;
      return number === standard;
    });
  };
  console.log(checkElement(1));
  console.log(checkElement(2));
}.call(this));
/* Generated by Continuation.js v0.1.2 */
//@ sourceMappingURL=abc.js.map

Which seems wrong for that return is in the function getElement's callback. Thus checkElement returns nothing.

More, when use

node abc.js

it gives

undefined
undefined

other than expected

true
false

ECMAScript 6 is not supported

This project is still alive? Can you please add support for new version JS languege.

Now, if continuation meet token like () => {} it obtain error:

Error: Line 15: Unexpected token => in undefined
at Object.parse (G:\ShepherdProject\cont8doo\node_modules\continuation\lib\parser.js:18:11)
at Object.exports.compile (G:\ShepherdProject\cont8doo\node_modules\continuation\continuation.js:29:20)
at compile (G:\ShepherdProject\cont8doo\node_modules\continuation\lib\cli.js:166:25)

Running compiler from the browser

My project does not use a module loading system such as RequireJS or AMD, so I am a bit of a loss at how to run the compiler from the browser.

Can the continuation compiler be run from the browser? If so, is there an example for that?

module searching terminates unexpectedly at certain directory

suppose the source tree is

/path/to/root
         |
         +--sub
         |  |
         |  +--main.js
         |
         +--node_modules
            |
            +--aaa
               |
               +--index.js

and main.js is

require('aaa');
console.log('sub/main.js');

while index.js is

console.log("this is aaa");

and below is the issue

% pwd
/path/to/root
% continuation sub/main.js
module.js:340
    throw err;
          ^
Error: Cannot find module 'aaa'
  at Function.Module._resolveFilename (module.js:338:15)
  at Function.Module._load (module.js:280:25)
  at Module.require (module.js:364:17)
  at require (module.js:380:17)
  at Object.<anonymous> (sub/main.js:1:69)
  at Module._compile (module.js:456:26)
  at executeTopModule (/usr/local/lib/node_modules/continuation/lib/cli.js:131:14)
  at Object.exports.main (/usr/local/lib/node_modules/continuation/lib/cli.js:86:7)
  at Object.<anonymous> (/usr/local/lib/node_modules/continuation/bin/continuation:3:5)
  at Module._compile (module.js:456:26)
  at Object.Module._extensions..js (module.js:474:10)
  at Module.load (module.js:356:32)
  at Function.Module._load (module.js:312:12)
  at Function.Module.runMain (module.js:497:10)
  at startup (node.js:119:16)
  at node.js:906:3
% continuation ./sub/main.js
this is aaa
sub/main.js
% continuation --version 
0.1.5
% node -v
v0.10.32

Strange behaviour with hoisted function

The following example:

errorinAsync(null, obtain());

function errorinAsync(options, callback){
    options = options || {};
    setTimeout(function(){
        return callback(new Error("This could be caught"));
    },1000);

}

Does not run, the errorInAsync function is included in the wrong scope in the compiled output:

var _$err;
errorinAsync(null, function () {
  _$err = arguments[0];
  if (_$err)
    throw _$err;
  function errorinAsync(options, callback) {
    options = options || {};
    setTimeout(function () {
      return callback(new Error('This could be caught'));
    }, 1000);
  }
});

`this` get lost in try block

 a={}
  a.b=(cb)->
    console.log this
    try
      console.log this
      this.b cont()
    catch err
      console.error err
  a.b()

the output code is

(function () {
  var a;
  a = {};
  a.b = function (cb) {
    var err;
    console.log(this);
    (function (_$cont) {
      try {
        console.log(this);
        return this.b(function (arguments) {
          try {
            _$cont();
          } catch (_$err) {
            _$cont(_$err);
          }
        }.bind(this, arguments));
      } catch (_$err) {
        _$cont(_$err);
      }
    }(function (_error) {
      if (_error !== undefined) {
        err = _error;
        return console.error(err);
      }
    }));
  };
  a.b();
}.call(this));
/* Generated by Continuation.js v0.1.7 */

Apparently, this get lost in the structure

(function (_$cont) {
  //...
})(function (_error) {
})

The compiler allow non-lvars as argument to cont() etc.

In other words, the compiler does not check whether the arguments to cont() etc.
are assignable. Here is an example:

// Source
async(stuff, cont(err, result+4));
bar(result+1);

// Output
var err;
async(stuff, function () {
  err = arguments[0];
  (result + 4) = arguments[1];
  bar(result + 1);
});
/* Generated by Continuation.js v0.1.3 */

This is always an error. You cannot assign to (result + 4). Actually, you can also
write 4 instead result + 4 and you will get 4 = arguments[1];!

Support source maps

Cool project! I really like how readable the generated code is (especially compared to Streamline, Tame etc). It'd be nice if it also supported source maps. Those are files that map locations in the source to locations in the generated code to make debugging easier.

Escodegen already supports source maps, so most of the hard work should hopefully be already done. But when the parser converts the AST nodes using syntax.factory, their "loc" property is lost. They need to keep it for source maps to work. (As for new nodes that weren't in the original AST, I guess their "loc" should just be null.)

Perhaps that's the only required change (well, plus adding the CLI option itself), but I'm not sure.

Wrong binding of `this` inside `if`/`while/`for`

Sample

this.name = 'outter';

function inner() {
  if (true) {
    setTimeout(cont(), 100);
    console.log(this.name);
  }
};

var o = {
  name: 'inner',
  inner: inner
};

console.log(this.name);
o.inner();

Execution result

The output result shoud be

outter
inner

But we got

outter
undefined

Compiled code

var o;
this.name = 'outter';
function inner() {
  (function (_$cont) {
    if (true) {
      setTimeout(function (arguments) {
        console.log(this.name);
        _$cont();
      }.bind(this, arguments), 100);
    } else {
      _$cont();
    }
  }(function (_$err) {
    if (_$err !== undefined)
      return _$cont(_$err);
  }));
}
o = {
  name: 'inner',
  inner: inner
};
o.inner();
console.log(this.name);
/* Generated by Continuation.js v0.1.4 */

I think the wrong context of function (_$cont) causes this bug, I will fix it soon.

continuous return value instead of continuous passsing style?

Hi, great job there,
is it possible to implement a trasformation which makes it possible to pass return values on the left side of the expression?
example:

    var value = async_call(arg1, arg2, obtain);

Do you think it's hard to implement? Any suggestion about that?
Thank you very much!

Move 'use strict' above

function test() {
    'use strict';
    f(obtain());
}

Actual

function test() {
  var _$err;
  'use strict';
  f(function () {
    _$err = arguments[0];
    if (_$err)
      throw _$err;
  });
}

Add example for parallel array processing

I can't seem to work out how to do the equivalent of

async.each https://github.com/caolan/async#eacharr-iterator-callback

or

async.map https://github.com/caolan/async#maparr-iterator-callback

Is there any chance of an example of something like that? These are the only use cases keeping my project dependant on the async library and I would love to remove that dependency if possible as I prefer the simplicity of the syntax when using your library and the robust error trapping.

Heuristics for exceptions don't work

function test(ret) {
  throw undefined;
}

try {
  test();
} catch(e) {
  console.log('Exception1: ', e); // prints Exception1: undefined
}

try {
  test(cont(res));
} catch(e) {
  console.log('Excpetion2: ',e); // Never prints!
}

Substituting undefined for 42 will print 42 in both places.

Wrong context when using `cont()` in switch..case

Sample

this.name = 'outter';

function inner() {
  var a = "a";

  switch (a) {
  case "a":
    setTimeout(cont(), 100);
    // wrong content here
    console.log(this.name);
    break;
  }
};

var o = {
  name: 'inner',
  inner: inner
};

console.log(this.name);
o.inner();

Which compiles to

var o;
this.name = 'outter';
function inner() {
  var a;
  a = 'a';
  (function (_$cont) {
    function case_0(_$cont) {
      setTimeout(function (arguments) {
        console.log(this.name);
        _$cont();
      }.bind(this, arguments), 100);
    }
    switch (a) {
    case 'a':
      return case_0(_$cont);
    }
  }.bind(this)(function () {
  }));
}
o = {
  name: 'inner',
  inner: inner
};
console.log(this.name);
o.inner();
/* Generated by Continuation.js v0.1.5 */

As you can see it we defined a function called case_0 here, but we haven't bind this pointer correctly.
I think we should add case_0 = case_0.bind(this); to make case_0(_$cont); get the correct context.

challenging issue

// use continuation to create a function which can synced waiting for 1 second
var stop = function() {
setTimeout(continuation(), 1000);
};
console.log("start");
stop();
console.log("end");

// Readme:
// Due to this, I suggest to consider implement coroutine for javascript.
// we can implement "continuation" by using yield initiatively and resume by callback function.

Arguments scope bug

js code:

var read = function() {
  var content = 'abc';
  fs.readFile('a.txt', 'utf-8', cont(err, content));
};

will be compiled to

var read;
read = function () {
  var content, err;
  content = 'abc';
  fs.readFile('a.txt', 'utf-8', function (arguments, _$param1, _$param2) {
    err = _$param1;
    content = _$param2;
  }.bind(this, arguments));
};

the variable content is changed.

So, the correct compiled result is that:

var read;
read = function () {
  var content;
  content = 'abc';
  fs.readFile('a.txt', 'utf-8', function (arguments, _$param1, _$param2) {
    var content, err;
    err = _$param1;
    content = _$param2;
  }.bind(this, arguments));
};

What do you think about it?

Wrong try/catch behavior

The following code doesn't work:

function callme(cb) {
  cb();
}

function main(cb) {
  try {
    callme(cont());
    var result = 0;
    [10, 20, 30].forEach(function (i) {
      result += i;
      throw Error('oh noes');
    });
  }
  catch (e) {
    cb(e);
    return;
  }
  cb(null, result);
}

main(function (e,r) {
  console.log('main() finished with', e, r);
})

Output:

main() finished with [Error: oh noes] undefined
main() finished with [Error: oh noes] undefined
main() finished with [Error: oh noes] undefined
main() finished with null 60

main() "finishes" multiple times (i.e. the console.log callback is called more than one time), which should never happen.

It seems continuation.js messes with the forEach callback and tries to "callback-ize" it even though forEach is always serial (and the function body doesn't contain "cont" nor "obtain"). Perhaps the correct behavior with nested functions is to leave them alone (and transform them separately, depending on whether they use cont) -- though that's just a guess and I'm not sure if that wouldn't break other stuff.

using 'continue' in for (... in ...)

var console = require('console');

function async (ret) {
  ret(null, [1, 2, 3, 4, 5, 6]);
}

try {
  async(obtain(a));
  for (var i in a)
    if (i % 2 == 0) continue;
    else console.log(a[i]);
} catch (err) {
  console.log(err);
}

The iterator doesn't go forward with continue.

Portable continuations?

Are continuations portable? Specifically, could a continuation be serialized and sent across the network to be resumed elsewhere?

If that were possible you could potentially do some very interesting stuff with breaking down the barrier between client and server. I experimented with this idea a few years ago using Scala (which has a compiler plugin that does something similar to this project), you can learn more about these ideas here: http://swarmframework.org/

cont() and obtain() do not work when instantiating a class

The code in this function:

function t() {
    var csvPath = '/tmp/contacts.csv';
        parser  = new ContactDocParser(csvPath, cont());
}

gets compiled to

function t() {
    var csvPath = '/tmp/contacts.csv';
        parser  = new ContactDocParser(csvPath, cont());
}
/* Generated by Continuation.js v0.1.4 */

It just ignores it.
When I remove the new statement, it does replace the cont()

When using `cont()` in `if` block, the context in `if` is correct while the context after `if` is incorrect.

Sample

this.name = 'outter';

function inner() {
  if (true) {
    setTimeout(cont(), 100);
    // Correct context here.
    console.log(this.name);
  }
  // Wrong context here.
  console.log(this.name);
};

var o = {
  name: 'inner',
  inner: inner
};

console.log(this.name);
o.inner();

Which compiles to

var o;
this.name = 'outter';
function inner() {
  (function (_$cont) {
    if (true) {
      setTimeout(function (arguments) {
        console.log(this.name);
        _$cont();
      }.bind(this, arguments), 100);
    } else {
      _$cont();
    }
  }.bind(this)(function (_$err) {
    if (_$err !== undefined)
      return _$cont(_$err);
    console.log(this.name);
  }));
}
o = {
  name: 'inner',
  inner: inner
};
console.log(this.name);
o.inner();
/* Generated by Continuation.js v0.1.5 */

This part of the compiled result got the wrong context:

function (_$err) {
    if (_$err !== undefined)
      return _$cont(_$err);
    console.log(this.name);
  }

Nested BlockStatements are improperly normalized

Block statements disappear.

{ x++; }
alert(cont());

is compiled to:

alert(function () {
});
/* Generated by Continuation.js v0.1.1 */

I'm working on a fix (and refactoring). A pull request should be ready soon.

Bizarre behavior when throw exceptions without try in a continuation block

var test = function(callback) {
    console.log('called');
    callback(null);
}

function main() {
    try {
        test(obtain(a));
    } catch (e) {
        console.log('error by obtain', e);
    }
    throw 'a';
}

try {
    main();
} catch (e) {
    console.log('error by main', e);
}

Expected:

called
error by main a

Actual:

called
error by obtain a
error by obtain a
error by main a

function declaration should goes to the top level

test();
setTimeout(cont(), 100);
function test() {
  console.log('test');
}

Which compiles to

test();
setTimeout(function (arguments) {
  function test() {
    console.log('test');
  }
}.bind(this, arguments), 100);

This is incorrect.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.