Skip to content

Instantly share code, notes, and snippets.

@remy
Created February 18, 2012 12:06
Show Gist options
  • Save remy/1859023 to your computer and use it in GitHub Desktop.
Save remy/1859023 to your computer and use it in GitHub Desktop.
Waits for functions to complete before running complete

Unfinished and not tested beyond my own case.

Usage

var wait = new Wait();
wait.complete(function () {
  console.log('we are done - now report');
});

$.get(url, wait.until(function (data) {
  // do something with data
});

db.users.find(wait.until(function (err, docs) {
  // we've found users in the mongo db
}));
Wait = function (complete) {
if (complete) this.oncomplete = complete;
};
Wait.prototype = {
debug: false,
log: function () {
if (!this.debug) return;
var args = [].slice.apply(arguments);
if (typeof args[0] == 'string') args[0] = '[wait] ' + args[0];
else args.unshift('[wait]');
console.log.apply(console, args);
},
oncomplete: function () {},
complete: function (fn) {
if (fn === undefined) {
this.oncomplete();
} else {
this.oncomplete = fn;
}
},
tasks: 0,
done: function () {
this.tasks--;
this.log('tasks left: ' + this.tasks);
if (this.tasks == 0) {
this.log('triggering complete')
this.complete();
}
},
until: function (task, context) {
var self = this,
name = (arguments.callee.name || 'anonymous');
this.tasks++;
context || (context = this);
this.log('new task: %s, total: %d', (arguments.callee.name || 'anonymous'), this.tasks);
return function () {
self.log('running %s', name);
var ret,
args = [].slice.apply(arguments);
// args.push(self.done);
try {
ret = task.apply(context, args);
} catch (e) {
console.error(e);
}
self.done();
return ret;
};
},
run: function (task, context) {
return this.add(task, context)();
}
};
if (typeof module !== undefined && module.exports !== undefined) {
module.exports = Wait;
}
@briancavalier
Copy link

Maybe have a look at when.js's when.all and when.reduce. They can join multiple tasks, and might do what you need. Here's a quick take on the original wait usage with when.js:

var when, apply, p1, p2;

when = require('when');
apply = require('when/apply');

var p1, p2;

p1 = $.get(url);

p2 = when.defer();
db.users.find(function (err, docs) {
  // we've found users in the mongo db
  p2.resolve(docs);
});

when.all([p1, p2],
    function(results) {
        // results[0] is p1 result
        // results[1] is p2 result
        console.log('we are done - now report');
    }
);

// Or use when/apply to spread results onto function args
when.all([p1, p2],
    apply(function(data, docs) {
        console.log('we are done - now report');
    })
);

// Could also use when.reduce (promise-aware Array.proto.reduce)
// to reduce the results.
// Here's a simple string concat
when.reduce([p1, p2],
    function(finalResult, current) {
        return finalResult + current;
    }, '') // initial value is empty string
.then(
    function(finalResult) {
        console.log('we are done - now report');    
    }
);

@unscriptable
Copy link

Unlike jQuery's Deferred, when.js is compliant with the defacto standard (CommonJS Promises/A), runs in browsers and node (and probably RingoJS), and even converts non-compliant promises like $.Deferred to compliant ones. #WIN

@briancavalier
Copy link

FWIW, yep, when.js 1.0.2 (probably earlier versions, too) works in Ringo 0.8.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment