| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- "use strict";
- /*
- * $asyncbind has multiple uses, depending on the parameter list. It is in Function.prototype, so 'this' is always a function
- *
- * 1) If called with a single argument (this), it is used when defining an async function to ensure when
- * it is invoked, the correct 'this' is present, just like "bind". For legacy reasons, 'this' is given
- * a memeber 'then' which refers to itself.
- * 2) If called with a second parameter ("catcher") and catcher!==true it is being used to invoke an async
- * function where the second parameter is the error callback (for sync exceptions and to be passed to
- * nested async calls)
- * 3) If called with the second parameter===true, it is the same use as (1), but the function is wrapped
- * in an 'Promise' as well bound to 'this'.
- * It is the same as calling 'new Promise(this)', where 'this' is the function being bound/wrapped
- * 4) If called with the second parameter===0, it is the same use as (1), but the function is wrapped
- * in a 'LazyThenable', which executes lazily and can resolve synchronously.
- * It is the same as calling 'new LazyThenable(this)' (if such a type were exposed), where 'this' is
- * the function being bound/wrapped
- */
- function processIncludes(includes,input) {
- var src = input.toString() ;
- var t = "return "+src ;
- var args = src.match(/.*\(([^)]*)\)/)[1] ;
- var re = /['"]!!!([^'"]*)['"]/g ;
- var m = [] ;
- while (1) {
- var mx = re.exec(t) ;
- if (mx)
- m.push(mx) ;
- else break ;
- }
- m.reverse().forEach(function(e){
- t = t.slice(0,e.index)+includes[e[1]]+t.substr(e.index+e[0].length) ;
- }) ;
- t = t.replace(/\/\*[^*]*\*\//g,' ').replace(/\s+/g,' ') ;
- return new Function(args,t)() ;
- }
- var $asyncbind = processIncludes({
- zousan:require('./zousan').toString(),
- thenable:require('./thenableFactory').toString()
- },
- function $asyncbind(self,catcher) {
- "use strict";
- if (!Function.prototype.$asyncbind) {
- Object.defineProperty(Function.prototype,"$asyncbind",{value:$asyncbind,enumerable:false,configurable:true,writable:true}) ;
- }
- if (!$asyncbind.trampoline) {
- $asyncbind.trampoline = function trampoline(t,x,s,e,u){
- return function b(q) {
- while (q) {
- if (q.then) {
- q = q.then(b, e) ;
- return u?undefined:q;
- }
- try {
- if (q.pop) {
- if (q.length)
- return q.pop() ? x.call(t) : q;
- q = s;
- } else
- q = q.call(t)
- } catch (r) {
- return e(r);
- }
- }
- }
- };
- }
- if (!$asyncbind.LazyThenable) {
- $asyncbind.LazyThenable = '!!!thenable'();
- $asyncbind.EagerThenable = $asyncbind.Thenable = ($asyncbind.EagerThenableFactory = '!!!zousan')();
- }
- function boundThen() {
- return resolver.apply(self,arguments);
- }
- var resolver = this;
- switch (catcher) {
- case true:
- return new ($asyncbind.Thenable)(boundThen);
- case 0:
- return new ($asyncbind.LazyThenable)(boundThen);
- case undefined:
- /* For runtime compatibility with Nodent v2.x, provide a thenable */
- boundThen.then = boundThen ;
- return boundThen ;
- default:
- return function(){
- try {
- return resolver.apply(self,arguments);
- } catch(ex) {
- return catcher(ex);
- }
- }
- }
- }) ;
- function $asyncspawn(promiseProvider,self) {
- if (!Function.prototype.$asyncspawn) {
- Object.defineProperty(Function.prototype,"$asyncspawn",{value:$asyncspawn,enumerable:false,configurable:true,writable:true}) ;
- }
- if (!(this instanceof Function)) return ;
- var genF = this ;
- return new promiseProvider(function enough(resolve, reject) {
- var gen = genF.call(self, resolve, reject);
- function step(fn,arg) {
- var next;
- try {
- next = fn.call(gen,arg);
- if(next.done) {
- if (next.value !== resolve) {
- if (next.value && next.value===next.value.then)
- return next.value(resolve,reject) ;
- resolve && resolve(next.value);
- resolve = null ;
- }
- return;
- }
- if (next.value.then) {
- next.value.then(function(v) {
- step(gen.next,v);
- }, function(e) {
- step(gen.throw,e);
- });
- } else {
- step(gen.next,next.value);
- }
- } catch(e) {
- reject && reject(e);
- reject = null ;
- return;
- }
- }
- step(gen.next);
- });
- }
- // Initialize async bindings
- $asyncbind() ;
- $asyncspawn() ;
- // Export async bindings
- module.exports = {
- $asyncbind:$asyncbind,
- $asyncspawn:$asyncspawn
- };
|