示例#1
0
	exports.funnel = function(max) {
		max = max == null ? -1 : max;
		if (max === 0) max = funnel.defaultSize;
		if (typeof max !== "number") throw new Error("bad max number: " + max);
		var queue = [],
			active = 0,
			closed = false;

		var funCb = function(callback, fn) {
				if (callback == null) return future(funCb, arguments, 0);
				//console.log("FUNNEL: active=" + active + ", queued=" + queue.length);
				if (max < 0 || max == Infinity) return galaxy.unstar(fn,0)(  callback);

				queue.push({
					fn: fn,
					cb: callback
				});

				function _doOne() {
					var current = queue.splice(0, 1)[0];
					if (!current.cb) return current.fn();
					active++;
					galaxy.unstar(current.fn,0)(  function(err, result) {
						active--;
						if (!closed) {
							current.cb(err, result);
							while (active < max && queue.length > 0) _doOne();
						}
					});
				}

				while (active < max && queue.length > 0) _doOne();
			};	
		var fun = galaxy.star(funCb, 0);

		fun.close = function() {
			queue = [], closed = true;
		};
		return fun;
	};
示例#2
0
(function(exports) {
	"use strict";
	var globals = require('streamline/lib/globals');
	var dir = 'streamline/lib/' + globals.runtime;
	var builtins = require(dir + '/builtins');
	/// !nodoc
	/// Obsolete API
	/// 
	/// This API is obsolete. Use `array.forEach_`, `array.map_`, ... instead.
	/// 
	/// * `flows.each(_, array, fn, [thisObj])`  
	///   applies `fn` sequentially to the elements of `array`.  
	///   `fn` is called as `fn(_, elt, i)`.
	exports.each = function*(_, array, fn, thisObj) {
		return (array && array.length) ? (yield array.forEach_(_, fn, thisObj)) : undefined;
	};
	/// * `result = flows.map(_, array, fn, [thisObj])`  
	///   transforms `array` by applying `fn` to each element in turn.  
	///   `fn` is called as `fn(_, elt, i)`.
	exports.map = function*(_, array, fn, thisObj) {
		return array ? (yield array.map_(_, fn, thisObj)) : array;
	};
	/// * `result = flows.filter(_, array, fn, [thisObj])`  
	///   generates a new array that only contains the elements that satisfy the `fn` predicate.  
	///   `fn` is called as `fn(_, elt)`.
	exports.filter = function*(_, array, fn, thisObj) {
		return array ? (yield array.filter_(_, fn, thisObj)) : array;
	};
	/// * `bool = flows.every(_, array, fn, [thisObj])`  
	///   returns true if `fn` is true on every element (if `array` is empty too).  
	///   `fn` is called as `fn(_, elt)`.
	exports.every = function*(_, array, fn, thisObj) {
		return array ? (yield array.every_(_, fn, thisObj)) : undefined;
	};
	/// * `bool = flows.some(_, array, fn, [thisObj])`  
	///   returns true if `fn` is true for at least one element.  
	///   `fn` is called as `fn(_, elt)`.
	exports.some = function*(_, array, fn, thisObj) {
		return array ? (yield array.some_(_, fn, thisObj)) : undefined;
	};
	/// * `result = flows.reduce(_, array, fn, val, [thisObj])`  
	///   reduces by applying `fn` to each element.  
	///   `fn` is called as `val = fn(_, val, elt, i, array)`.
	exports.reduce = function*(_, array, fn, v, thisObj) {
		return array ? (yield array.reduce_(_, fn, v, thisObj)) : v;
	};
	/// * `result = flows.reduceRight(_, array, fn, val, [thisObj])`  
	///   reduces from end to start by applying `fn` to each element.  
	///   `fn` is called as `val = fn(_, val, elt, i, array)`.
	exports.reduceRight = function*(_, array, fn, v, thisObj) {
		return array ? (yield array.reduceRight_(_, fn, v, thisObj)) : v;
	};

	/// * `array = flows.sort(_, array, compare, [beg], [end])`  
	///   sorts the array.  
	///   `compare` is called as `cmp = compare(_, elt1, elt2)`
	///   
	///   Note: this function _changes_ the original array (and returns it)
	exports.sort = function*(_, array, compare, beg, end) {
		return array ? (yield array.sort_(_, compare, beg, end)) : array;
	};
	/// 
	/// ## Object utility (obsolete)
	/// 
	/// This API is obsolete. Use `Object.keys(obj).forEach_` instead.
	/// 
	/// * `flows.eachKey(_, obj, fn)`  
	///   calls `fn(_, key, obj[key])` for every `key` in `obj`.
	exports.eachKey = function*(_, obj, fn, thisObj) {
		return (yield (obj ? Object.keys(obj) : []).forEach_(_, function*(_, elt) {
			(yield fn.call(thisObj, _, elt, obj[elt]));
		}));
	};
	// deprecated -- don't document 
	exports.spray = function(fns, max) {
		return new

		function() {
			var funnel = exports.funnel(max);
			this.collect = function*(_, count, trim) {
				return (yield galaxy.invoke((function(callback) {
					if (typeof(callback) != "function") throw new Error("invalid call to collect: no callback");
					var results = trim ? [] : new Array(fns.length);
					count = count < 0 ? fns.length : Math.min(count, fns.length);
					if (count == 0) return callback(null, results);
					var collected = 0;
					for (var i = 0; i < fns.length; i++) {
						(function(i) {
							galaxy.unstar(funnel,0)(  function(err, result) {
								if (err) return callback(err);
								if (trim) results.push(result);
								else results[i] = result;
								if (++collected == count) return callback(null, results);
							}, fns[i]);
						})(i);
					}
				}), "call", [this, _], 1));
			};
			this.collectOne = function*(_) {
				var result = (yield this.collect(_, 1, true));
				return result && result[0];
			};
			this.collectAll = function*(_) {
				return (yield this.collect(_, -1, false));
			};
		};

	};

	
	/// * `fun = flows.funnel(max)`  
	///   limits the number of concurrent executions of a given code block.
	/// 
	/// The `funnel` function is typically used with the following pattern:
	/// 
	/// ``` javascript
	/// // somewhere
	/// var myFunnel = flows.funnel(10); // create a funnel that only allows 10 concurrent executions.
	/// 
	/// // elsewhere
	/// myFunnel(_, function(_) { /* code with at most 10 concurrent executions */ });
	/// ```
	/// 
	/// The `diskUsage2.js` example demonstrates how these calls can be combined to control concurrent execution.
	/// 
	/// The `funnel` function can also be used to implement critical sections. Just set funnel's `max` parameter to 1.
	/// 
	/// If `max` is set to 0, a default number of parallel executions is allowed. 
	/// This default number can be read and set via `flows.funnel.defaultSize`.  
	/// If `max` is negative, the funnel does not limit the level of parallelism.
	/// 
	/// The funnel can be closed with `fun.close()`.  
	/// When a funnel is closed, the operations that are still in the funnel will continue but their callbacks
	/// won't be called, and no other operation will enter the funnel.
	exports.funnel = builtins.funnel;

	/// 
	/// * `results = flows.collect(_, futures)`  
	///   collects the results of an array of futures
	exports.collect = function*(_, futures) {
		return futures && (yield futures.map_(_, function*(_, future) {
			return (yield future(_));
		}));
	};

	// Obsolete API - use require('streamline/lib/globals').context instead
	var globals = require("streamline/lib/globals");
	exports.setContext = function(ctx) {
		var old = globals.context;
		globals.context = ctx;
		return old;
	};
	exports.getContext = function() {
		return globals.context;
	};

	/// 
	/// * `flows.nextTick(_)`  
	///   `nextTick` function for both browser and server.  
	///   Aliased to `process.nextTick` on the server side.
	var nextTick = typeof process === "object" && typeof process.nextTick === "function" ? process.nextTick : function(cb) {
		cb();
	};

	exports.nextTick =  function*(_) {
		(yield galaxy.invoke(null, nextTick, [_], 0));
	};

	exports.setTimeout = function(fn, millis) {
		return setTimeout(function() {
			galaxy.spin.call(this, fn(false), 0);
		}, millis);
	};

	exports.setInterval = function(fn, millis) {
		return setInterval(function() {
			galaxy.spin.call(this, fn(false), 0);
		}, millis);
	};

	exports.setImmediate = function*(_, fn, thisObj) {
		(yield galaxy.invoke(null, (function(cb) {
			setImmediate(function() {
				galaxy.unstar(fn.bind(thisObj),0)(  cb);
			});
		}), [_], 0));
	};

	exports.sleep = function*(_, millis) {
		return (yield galaxy.invoke(null, setTimeout, [_, millis], 0));
	};

	exports.eventHandler = function(fn) {
		return function() {
			var that = this;
			var args = Array.prototype.slice(arguments, 0);
			return galaxy.unstar((function*(_) {
				return (yield fn.apply_(_, that, args, 0));
			}),0)(  function(err) {
				if (err) throw err;
			});
		};
	};

	//   Obsolete. Use `fn.apply_` instead.
	exports.apply = function* apply(_, fn, thisObj, args, index) {
		return (yield fn.apply_(_, thisObj, args, index));
	};

	exports.callWithTimeout = galaxy.star(function(cb, fn, millis) {
			var tid = setTimeout(function() {
				if (cb) {
					var ex = new Error("timeout");
					ex.code = "ETIMEOUT";
					ex.errno = "ETIMEOUT";
					cb(ex);
					cb = null;
				}
			}, millis);
			galaxy.unstar(fn,0)(  function(err, result) {
				if (cb) {
					clearTimeout(tid);
					cb(err, result);
					cb = null;
				}
			});
	}, 0);

	
})(typeof exports !== 'undefined' ? exports : (Streamline.flows = Streamline.flows || {}));