refactoring graphiteSrv to use angular promises, removed dependency on RQ
This commit is contained in:
@@ -43,20 +43,12 @@ require.config({
|
||||
|
||||
modernizr: '../vendor/modernizr-2.6.1',
|
||||
elasticjs: '../vendor/elasticjs/elastic-angular-client',
|
||||
rq: '../vendor/rq',
|
||||
setImmediate: '../vendor/setImmediate',
|
||||
|
||||
},
|
||||
shim: {
|
||||
underscore: {
|
||||
exports: '_'
|
||||
},
|
||||
|
||||
rq: {
|
||||
deps: ['setImmediate'],
|
||||
exports: 'RQ'
|
||||
},
|
||||
|
||||
angular: {
|
||||
deps: ['jquery','config'],
|
||||
exports: 'angular'
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
define([
|
||||
'jquery',
|
||||
'rq',
|
||||
'underscore',
|
||||
'config'
|
||||
],
|
||||
function ($, RQ, _, config) {
|
||||
'use strict';
|
||||
|
||||
|
||||
function build_graphite_options(options) {
|
||||
var clean_options = [];
|
||||
var graphite_options = ['target', 'targets', 'from', 'until', 'rawData', 'format', 'maxDataPoints'];
|
||||
|
||||
options['format'] = 'json';
|
||||
|
||||
$.each(options, function (key, value) {
|
||||
if ($.inArray(key, graphite_options) === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (key === "targets") {
|
||||
$.each(value, function (index, value) {
|
||||
if (!value.hide) {
|
||||
clean_options.push("target=" + encodeURIComponent(value.target));
|
||||
}
|
||||
});
|
||||
} else if (value !== null) {
|
||||
clean_options.push(key + "=" + encodeURIComponent(value));
|
||||
}
|
||||
});
|
||||
return clean_options;
|
||||
}
|
||||
|
||||
function loadGraphiteData(options)
|
||||
{
|
||||
return function (requestion) {
|
||||
var graphOptions = {
|
||||
from: $.plot.formatDate(options.range.from, '%H%:%M_%Y%m%d'),
|
||||
until: $.plot.formatDate(options.range.to, '%H%:%M_%Y%m%d'),
|
||||
targets: options.targets,
|
||||
maxDataPoints: options.maxDataPoints
|
||||
};
|
||||
|
||||
var graphiteParameters = build_graphite_options(graphOptions);
|
||||
getGraphiteData(graphiteParameters)
|
||||
.done(function(data) {
|
||||
requestion(data);
|
||||
})
|
||||
.fail(function() {
|
||||
requestion(null, 'Error in ajax call to graphite');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function getGraphiteData(parameters) {
|
||||
return $.ajax({
|
||||
accepts: { text: 'application/json' },
|
||||
cache: false,
|
||||
dataType: 'json',
|
||||
url: config.graphiteUrl + '/render/',
|
||||
type: "POST",
|
||||
data: parameters.join('&')
|
||||
});
|
||||
}
|
||||
|
||||
function match(targets, graphiteTargetStr) {
|
||||
var found = targets[0];
|
||||
|
||||
for (var i = 0; i < targets.length; i++) {
|
||||
if (targets[i].target === graphiteTargetStr) {
|
||||
found = targets[i];
|
||||
break;
|
||||
}
|
||||
if(targets[i].target.match("'" + graphiteTargetStr + "'")) {
|
||||
found = targets[i];
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
return {
|
||||
loadGraphiteData: loadGraphiteData,
|
||||
match: match
|
||||
};
|
||||
});
|
||||
@@ -19,8 +19,6 @@ define([
|
||||
'kbn',
|
||||
'moment',
|
||||
'./timeSeries',
|
||||
'./graphiteSrv',
|
||||
'rq',
|
||||
'jquery.flot',
|
||||
'jquery.flot.events',
|
||||
'jquery.flot.selection',
|
||||
@@ -29,14 +27,15 @@ define([
|
||||
'jquery.flot.stack',
|
||||
'jquery.flot.stackpercent'
|
||||
],
|
||||
function (angular, app, $, _, kbn, moment, timeSeries, graphiteSrv, RQ) {
|
||||
function (angular, app, $, _, kbn, moment, timeSeries) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('kibana.panels.graphite', []);
|
||||
app.useModule(module);
|
||||
|
||||
module.controller('graphite', function($scope, $rootScope, filterSrv) {
|
||||
module.controller('graphite', function($scope, $rootScope, filterSrv, graphiteSrv, $timeout) {
|
||||
|
||||
$scope.panelMeta = {
|
||||
modals : [
|
||||
{
|
||||
@@ -211,7 +210,7 @@ function (angular, app, $, _, kbn, moment, timeSeries, graphiteSrv, RQ) {
|
||||
|
||||
|
||||
$scope.init = function() {
|
||||
$scope.openConfigureModal();
|
||||
//$scope.openConfigureModal();
|
||||
|
||||
// Hide view options by default
|
||||
$scope.options = false;
|
||||
@@ -313,84 +312,71 @@ function (angular, app, $, _, kbn, moment, timeSeries, graphiteSrv, RQ) {
|
||||
var range = $scope.get_time_range();
|
||||
var interval = $scope.get_interval(range);
|
||||
|
||||
var graphiteLoadOptions = {
|
||||
var graphiteQuery = {
|
||||
range: range,
|
||||
targets: $scope.panel.targets,
|
||||
maxDataPoints: $scope.panel.span * 50
|
||||
};
|
||||
|
||||
var result = RQ.sequence([
|
||||
graphiteSrv.loadGraphiteData(graphiteLoadOptions),
|
||||
$scope.receiveGraphiteData(range, interval)
|
||||
]);
|
||||
|
||||
result(function (data, failure) {
|
||||
$scope.panelMeta.loading = false;
|
||||
|
||||
if (failure || !data) {
|
||||
$scope.panel.error = 'Failed to do fetch graphite data: ' + failure;
|
||||
$scope.$apply();
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.$apply();
|
||||
|
||||
// Tell the histogram directive to render.
|
||||
$scope.$emit('render', data);
|
||||
});
|
||||
|
||||
return graphiteSrv.query(graphiteQuery)
|
||||
.then(function(results) {
|
||||
$scope.panelMeta.loading = false;
|
||||
var data = $scope.receiveGraphiteData(results, range, interval)
|
||||
$scope.$emit('render', data);
|
||||
})
|
||||
.then(null, function(err) {
|
||||
$scope.panel.error = err.message || "Graphite HTTP Request Error";
|
||||
});
|
||||
};
|
||||
|
||||
$scope.receiveGraphiteData = function(range, interval) {
|
||||
$scope.receiveGraphiteData = function(results, range, interval) {
|
||||
var results = results.data;
|
||||
$scope.legend = [];
|
||||
var data = [];
|
||||
|
||||
return function receive_graphite_data_requestor(requestion, results) {
|
||||
$scope.legend = [];
|
||||
var data = [];
|
||||
if(results.length === 0 ) {
|
||||
throw { message: 'no data in response from graphite' };
|
||||
}
|
||||
|
||||
if(results.length === 0 ) {
|
||||
requestion('no data in response from graphite');
|
||||
}
|
||||
//console.log('Data from graphite:', results);
|
||||
//console.log('nr datapoints from graphite: %d', results[0].datapoints.length);
|
||||
|
||||
//console.log('Data from graphite:', results);
|
||||
//console.log('nr datapoints from graphite: %d', results[0].datapoints.length);
|
||||
var tsOpts = {
|
||||
interval: interval,
|
||||
start_date: range && range.from,
|
||||
end_date: range && range.to,
|
||||
fill_style: 'no'
|
||||
};
|
||||
|
||||
var tsOpts = {
|
||||
interval: interval,
|
||||
start_date: range && range.from,
|
||||
end_date: range && range.to,
|
||||
fill_style: 'no'
|
||||
};
|
||||
|
||||
_.each(results, function(targetData) {
|
||||
var time_series = new timeSeries.ZeroFilled(tsOpts);
|
||||
|
||||
_.each(targetData.datapoints, function(valueArray) {
|
||||
if (valueArray[0]) {
|
||||
time_series.addValue(valueArray[1] * 1000, valueArray[0]);
|
||||
}
|
||||
});
|
||||
|
||||
var target = graphiteSrv.match($scope.panel.targets, targetData.target);
|
||||
|
||||
var seriesInfo = {
|
||||
alias: targetData.target,
|
||||
color: $scope.colors[data.length],
|
||||
enable: true,
|
||||
yaxis: target.yaxis || 1
|
||||
};
|
||||
|
||||
$scope.legend.push(seriesInfo);
|
||||
|
||||
data.push({
|
||||
info: seriesInfo,
|
||||
time_series: time_series,
|
||||
yaxis: target.yaxis || 1
|
||||
});
|
||||
_.each(results, function(targetData) {
|
||||
var time_series = new timeSeries.ZeroFilled(tsOpts);
|
||||
|
||||
_.each(targetData.datapoints, function(valueArray) {
|
||||
if (valueArray[0]) {
|
||||
time_series.addValue(valueArray[1] * 1000, valueArray[0]);
|
||||
}
|
||||
});
|
||||
|
||||
requestion(data);
|
||||
};
|
||||
var target = graphiteSrv.match($scope.panel.targets, targetData.target);
|
||||
|
||||
var seriesInfo = {
|
||||
alias: targetData.target,
|
||||
color: $scope.colors[data.length],
|
||||
enable: true,
|
||||
yaxis: target.yaxis || 1
|
||||
};
|
||||
|
||||
$scope.legend.push(seriesInfo);
|
||||
|
||||
data.push({
|
||||
info: seriesInfo,
|
||||
time_series: time_series,
|
||||
yaxis: target.yaxis || 1
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
$scope.add_target = function() {
|
||||
@@ -413,7 +399,7 @@ function (angular, app, $, _, kbn, moment, timeSeries, graphiteSrv, RQ) {
|
||||
closeEditMode();
|
||||
}
|
||||
|
||||
setImmediate(function() {
|
||||
$timeout(function() {
|
||||
$scope.$emit('render');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ define([
|
||||
'./filterSrv',
|
||||
'./timer',
|
||||
'./panelMove',
|
||||
'./graphite/graphiteSrv',
|
||||
'./esVersion',
|
||||
'./keyboardManager',
|
||||
],
|
||||
|
||||
@@ -1,7 +1,86 @@
|
||||
define([
|
||||
'angular',
|
||||
'underscore',
|
||||
'jquery',
|
||||
'config'
|
||||
],
|
||||
function () {
|
||||
function (angular, _, $, config) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('kibana.services');
|
||||
|
||||
module.service('graphiteSrv', function($http) {
|
||||
|
||||
this.query = function(options) {
|
||||
var graphOptions = {
|
||||
from: $.plot.formatDate(options.range.from, '%H%:%M_%Y%m%d'),
|
||||
until: $.plot.formatDate(options.range.to, '%H%:%M_%Y%m%d'),
|
||||
targets: options.targets,
|
||||
maxDataPoints: options.maxDataPoints
|
||||
};
|
||||
|
||||
var params = buildGraphitePostParams(graphOptions);
|
||||
|
||||
var url = config.graphiteUrl + '/render/';
|
||||
return $http({
|
||||
method: 'POST',
|
||||
url: url,
|
||||
data: params.join('&'),
|
||||
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
|
||||
});
|
||||
};
|
||||
|
||||
this.match = function(targets, graphiteTargetStr) {
|
||||
var found = targets[0];
|
||||
|
||||
for (var i = 0; i < targets.length; i++) {
|
||||
if (targets[i].target === graphiteTargetStr) {
|
||||
found = targets[i];
|
||||
break;
|
||||
}
|
||||
if(targets[i].target.match("'" + graphiteTargetStr + "'")) {
|
||||
found = targets[i];
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
};
|
||||
|
||||
/*function getGraphiteData(parameters) {
|
||||
return $.ajax({
|
||||
accepts: { text: 'application/json' },
|
||||
cache: false,
|
||||
dataType: 'json',
|
||||
url: config.graphiteUrl + '/render/',
|
||||
type: "POST",
|
||||
data: parameters.join('&')
|
||||
});
|
||||
}
|
||||
*/
|
||||
function buildGraphitePostParams(options) {
|
||||
var clean_options = [];
|
||||
var graphite_options = ['target', 'targets', 'from', 'until', 'rawData', 'format', 'maxDataPoints'];
|
||||
|
||||
options['format'] = 'json';
|
||||
|
||||
$.each(options, function (key, value) {
|
||||
if ($.inArray(key, graphite_options) === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (key === "targets") {
|
||||
$.each(value, function (index, value) {
|
||||
if (!value.hide) {
|
||||
clean_options.push("target=" + encodeURIComponent(value.target));
|
||||
}
|
||||
});
|
||||
} else if (value !== null) {
|
||||
clean_options.push(key + "=" + encodeURIComponent(value));
|
||||
}
|
||||
});
|
||||
return clean_options;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
Vendored
-588
@@ -1,588 +0,0 @@
|
||||
/*
|
||||
rq.js
|
||||
|
||||
Douglas Crockford
|
||||
2013-10-11
|
||||
Public Domain
|
||||
|
||||
This package uses four kinds of functions:
|
||||
requestor
|
||||
requestion
|
||||
quash
|
||||
requestory
|
||||
|
||||
|
||||
requestor(requestion [, initial])
|
||||
may return a quash function
|
||||
|
||||
A requestor is a function that makes a request. Such a request need not
|
||||
be satisified immediately. It is likely that the request will not be
|
||||
satisified until some future turn. Requestors provide a means of dealing
|
||||
with future activities without blocking.
|
||||
|
||||
A requestor is a function that takes a requestion function as its first
|
||||
parameter, and optionally an initial value as its second parameter. The
|
||||
requestor uses the requestion to report its result. A requestor may
|
||||
optionally return a quash function that might be used to cancel the
|
||||
request, triggering the requestion function with a failure result.
|
||||
|
||||
The initial parameter contains a value that may be used to initialize the
|
||||
request. It is provided specifically for RQ.sequence, but it may be passed
|
||||
to any requestor.
|
||||
|
||||
|
||||
requestion(success, failure)
|
||||
returns undefined
|
||||
|
||||
A requestion function is a continuation or callback. It is used to deliver
|
||||
the result of a request. A requestion takes two arguments: success and
|
||||
failure. If the request succeeds, then the result will be passed to the
|
||||
requestion function as the success parameter, and the failure parameter
|
||||
will be undefined. If the request fails, then the requestion function will
|
||||
be passed the reason as the failure parameter. If failure is undefined,
|
||||
then the request succeeded. If failure is any other value, then the request
|
||||
failed.
|
||||
|
||||
|
||||
quash(reason)
|
||||
returns undefined
|
||||
|
||||
If a request is likely to be expensive to satisfy, the requestor may
|
||||
optionally return a quash function that would allow the request to be
|
||||
cancelled. A requestor is not required to return a quash function, and
|
||||
the quash function will not be guaranteed to cancel the request. The
|
||||
quash's reason argument may become the requestion's failure argument.
|
||||
|
||||
|
||||
requestory([arguments])
|
||||
returns a requestor function
|
||||
|
||||
A requestory is a factory function that produces a requestor function. A
|
||||
requestory function will usually take parameters that will customize or
|
||||
specialize a request. It is possible to write requestor functions by hand,
|
||||
but it is usually easier to generate them with requestories.
|
||||
|
||||
|
||||
The RQ object contains some requestory functions that permit the composition of
|
||||
requestors:
|
||||
|
||||
RQ.fallback(requestors, milliseconds)
|
||||
RQ.race(requestors, milliseconds)
|
||||
RQ.parallel(requestors, optionals, milliseconds, tilliseconds)
|
||||
RQ.sequence(requestors, milliseconds)
|
||||
|
||||
Each of these four requestory functions returns a requestor function that
|
||||
returns a quash function.
|
||||
|
||||
|
||||
RQ.fallback(requestors, milliseconds)
|
||||
|
||||
RQ.fallback returns a requestor function that will call the first element
|
||||
in the requestors array. If that is ultimately successful, its value will
|
||||
be passed to the requestion. But if it fails, the next element will be
|
||||
called, and so on. If none of the elements are successful, then the
|
||||
fallback fails. If any succeeds, then the fallback succeeds.
|
||||
|
||||
If the optional milliseconds argument is supplied, then if a request is not
|
||||
successful in the allotted time, then the fallback fails, and the pending
|
||||
requestor is cancelled.
|
||||
|
||||
|
||||
RQ.race(requestors [, milliseconds])
|
||||
|
||||
RQ.race returns a requestor that starts all of the functions in the
|
||||
requestors array in parallel. Its result is the result of the first of
|
||||
those requestors to successfully finish (all of the other requestors are
|
||||
cancelled). If all of those requestors fail, then the race fails.
|
||||
|
||||
If the optional milliseconds argument is supplied, then if no requestor has
|
||||
been successful in the allotted time, then the race fails, and all pending
|
||||
requestors are cancelled.
|
||||
|
||||
|
||||
RQ.parallel(requestors [, milliseconds])
|
||||
RQ.parallel(requestors, optionals [, milliseconds, [tilliseconds]])
|
||||
|
||||
RQ.parallel returns a requestor that processes many requestors in parallel,
|
||||
producing an array of all of the successful results. It can take two arrays
|
||||
of requests: Those that are required to produce results, and those that may
|
||||
optionally produce results. Each of the optional requestors has until all
|
||||
of the required requestors have finished, or until the optional
|
||||
tilliseconds timer has expired.
|
||||
|
||||
The result maps the requestors and optionals into a single array. The
|
||||
value produced by the first element of the requestors array provides the
|
||||
first element of the result.
|
||||
|
||||
If the optional milliseconds argument is supplied, then if all of the
|
||||
required requestors are not successful in the allotted time, then the
|
||||
parallel fails. If there are no required requestors, and if at least one
|
||||
optional requestor is successful within the allotted time, then the
|
||||
parallel succeeds.
|
||||
|
||||
|
||||
RQ.sequence(requestors [, milliseconds])
|
||||
|
||||
RQ.sequence returns a requestor that processes each element of the
|
||||
requestors array one at a time. Each will be passed the result of the
|
||||
previous. If all succeed, then the sequence succeeds, having the result of
|
||||
the last of the requestors. If any fail, then the sequence fails.
|
||||
|
||||
If the optional milliseconds argument is supplied, then if all of the
|
||||
requestors have not all completed in the allotted time, then the sequence
|
||||
fails and the pending requestor is cancelled.
|
||||
*/
|
||||
|
||||
/*global
|
||||
clearTimeout, setImmediate, setTimeout
|
||||
*/
|
||||
|
||||
/*properties
|
||||
array, evidence, fallback, freeze, forEach, index, isArray, length,
|
||||
message, method, milliseconds, name, parallel, race, sequence, value
|
||||
*/
|
||||
|
||||
var RQ = (function () {
|
||||
'use strict';
|
||||
|
||||
function expired(method, milliseconds) {
|
||||
|
||||
// Make an expired exception.
|
||||
|
||||
return {
|
||||
name: "expired",
|
||||
method: method,
|
||||
message: "expired after " + milliseconds,
|
||||
milliseconds: milliseconds
|
||||
};
|
||||
}
|
||||
|
||||
function check(method, requestors, milliseconds, optionals, tilliseconds) {
|
||||
|
||||
// Verify that the arguments are typed properly.
|
||||
|
||||
function is_function(value, index, array) {
|
||||
if (typeof value !== 'function') {
|
||||
var e = new TypeError("not a function");
|
||||
e.array = array;
|
||||
e.index = index;
|
||||
e.method = method;
|
||||
e.value = value;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// requestors must be an array of functions, and it may be empty only if
|
||||
// optionals is present.
|
||||
|
||||
if (optionals === undefined) {
|
||||
if (!Array.isArray(requestors) || requestors.length === 0) {
|
||||
throw new TypeError(method + " requestors");
|
||||
}
|
||||
} else {
|
||||
if (requestors && !Array.isArray(requestors)) {
|
||||
throw new TypeError(method + " requestors");
|
||||
}
|
||||
if (!Array.isArray(optionals) || optionals.length === 0) {
|
||||
throw new TypeError(method + " optionals");
|
||||
}
|
||||
optionals.forEach(is_function);
|
||||
}
|
||||
requestors.forEach(is_function);
|
||||
if (milliseconds &&
|
||||
(typeof milliseconds !== 'number' || milliseconds < 0)) {
|
||||
throw new TypeError(method + " milliseconds");
|
||||
}
|
||||
if (tilliseconds &&
|
||||
(typeof tilliseconds !== 'number' || tilliseconds < 0)) {
|
||||
throw new TypeError(method + " tilliseconds");
|
||||
}
|
||||
}
|
||||
|
||||
function check_requestion(method, requestion, initial) {
|
||||
if (typeof requestion !== 'function') {
|
||||
throw new TypeError(method + " requestion");
|
||||
}
|
||||
if (initial !== null && typeof initial === 'object') {
|
||||
Object.freeze(initial);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
fallback : function fallback(requestors, milliseconds) {
|
||||
|
||||
// RQ.fallback takes an array of requestor functions, and returns a requestor
|
||||
// that will call them each in order until it finds a successful outcome.
|
||||
|
||||
// If all of the requestor functions fail, then the fallback fails. If the time
|
||||
// expires, then work in progress is cancelled.
|
||||
|
||||
check("RQ.fallack", requestors, milliseconds);
|
||||
return function requestor(requestion, initial) {
|
||||
var cancel,
|
||||
timeout_id;
|
||||
|
||||
function finish(success, failure) {
|
||||
var r = requestion;
|
||||
cancel = null;
|
||||
if (r) {
|
||||
if (timeout_id) {
|
||||
clearTimeout(timeout_id);
|
||||
}
|
||||
requestion = null;
|
||||
timeout_id = null;
|
||||
return r(success, failure);
|
||||
}
|
||||
}
|
||||
|
||||
function quash(reason) {
|
||||
if (requestion && typeof cancel === 'function') {
|
||||
setImmediate(cancel, reason);
|
||||
}
|
||||
return finish(undefined, reason || true);
|
||||
}
|
||||
|
||||
check_requestion("RQ.fallack", requestion, initial);
|
||||
if (milliseconds) {
|
||||
timeout_id = setTimeout(function () {
|
||||
return quash(expired("RQ.fallback", milliseconds));
|
||||
}, milliseconds);
|
||||
}
|
||||
(function next(index, failure) {
|
||||
if (typeof requestion === 'function') {
|
||||
|
||||
// If there are no more requestors, then signal failure.
|
||||
|
||||
if (index >= requestors.length) {
|
||||
clearTimeout(timeout_id);
|
||||
cancel = null;
|
||||
return quash(failure);
|
||||
}
|
||||
|
||||
// If there is another requestor, call it in the next turn, passing the value
|
||||
// and a requestion that will take the next step.
|
||||
|
||||
var requestor = requestors[index];
|
||||
setImmediate(function () {
|
||||
var once = true;
|
||||
if (typeof requestion === 'function') {
|
||||
cancel = requestor(
|
||||
function requestion(success, failure) {
|
||||
if (once) {
|
||||
once = false;
|
||||
cancel = null;
|
||||
return failure === undefined
|
||||
? finish(success)
|
||||
: next(index + 1, failure);
|
||||
}
|
||||
},
|
||||
initial
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}(0));
|
||||
return quash;
|
||||
};
|
||||
},
|
||||
parallel: function parallel(requestors, optionals, milliseconds,
|
||||
tilliseconds) {
|
||||
|
||||
// RQ.parallel takes an array of requestors, and an optional second array of
|
||||
// requestors, and starts them all. It succeeds if all of the requestors in
|
||||
// the first array finish successfully before the time expires. The result
|
||||
// is an array collecting the results of all of the requestors.
|
||||
|
||||
if (typeof optionals === 'number') {
|
||||
milliseconds = optionals;
|
||||
tilliseconds = undefined;
|
||||
optionals = undefined;
|
||||
}
|
||||
check("RQ.parallel", requestors, milliseconds, optionals,
|
||||
tilliseconds);
|
||||
|
||||
return function requestor(requestion, initial) {
|
||||
var quashes = [],
|
||||
optionals_remaining,
|
||||
optionals_successes = 0,
|
||||
requestors_length = requestors.length,
|
||||
requestors_remaining = requestors.length,
|
||||
results = [],
|
||||
timeout_till,
|
||||
timeout_id;
|
||||
|
||||
function finish(success, failure) {
|
||||
var r = requestion;
|
||||
if (r) {
|
||||
requestion = null;
|
||||
if (timeout_id) {
|
||||
clearTimeout(timeout_id);
|
||||
timeout_id = null;
|
||||
}
|
||||
if (timeout_till) {
|
||||
clearTimeout(timeout_till);
|
||||
timeout_till = null;
|
||||
}
|
||||
quashes.forEach(function (quash) {
|
||||
if (typeof quash === 'function') {
|
||||
return setImmediate(quash, failure);
|
||||
}
|
||||
});
|
||||
quashes = null;
|
||||
results = null;
|
||||
return r(success, failure);
|
||||
}
|
||||
}
|
||||
|
||||
function quash(reason) {
|
||||
return finish(undefined, reason || true);
|
||||
}
|
||||
|
||||
check_requestion("RQ.parallel", requestion, initial);
|
||||
|
||||
// milliseconds, if specified, says take no longer to process this request. If
|
||||
// any of the required requestors are not successful by this time, the parallel
|
||||
// requestor fails.
|
||||
|
||||
if (milliseconds) {
|
||||
timeout_id = setTimeout(function () {
|
||||
timeout_id = null;
|
||||
return requestors_remaining === 0 &&
|
||||
(requestors_length > 0 ||
|
||||
optionals_successes > 0)
|
||||
? finish(results)
|
||||
: quash(expired("RQ.parallel", milliseconds));
|
||||
}, milliseconds);
|
||||
|
||||
// tilliseconds, if specified, gives more time for the optional requestors to
|
||||
// complete. Normally, the optional requestors have until all of the required
|
||||
// requestors finish. If tilliseconds is larger than milliseconds, milliseconds
|
||||
// wins.
|
||||
|
||||
}
|
||||
if (tilliseconds) {
|
||||
timeout_till = setTimeout(function () {
|
||||
timeout_till = null;
|
||||
if (requestors_remaining === 0) {
|
||||
return finish(results);
|
||||
}
|
||||
}, tilliseconds);
|
||||
}
|
||||
if (requestors) {
|
||||
requestors.forEach(function (requestor, index) {
|
||||
return setImmediate(function () {
|
||||
var once = true, cancel = requestor(
|
||||
function requestion(success, failure) {
|
||||
if (once && quashes) {
|
||||
once = false;
|
||||
quashes[index] = null;
|
||||
if (failure !== undefined) {
|
||||
return quash(failure);
|
||||
}
|
||||
results[index] = success;
|
||||
requestors_remaining -= 1;
|
||||
if (requestors_remaining === 0 &&
|
||||
!timeout_till) {
|
||||
return finish(results);
|
||||
}
|
||||
}
|
||||
},
|
||||
initial
|
||||
);
|
||||
if (quashes && quashes[index] === undefined) {
|
||||
quashes[index] = cancel;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
if (optionals) {
|
||||
optionals_remaining = optionals.length;
|
||||
optionals.forEach(function (requestor, index) {
|
||||
return setImmediate(function () {
|
||||
var once = true, cancel = requestor(
|
||||
function requestion(success, failure) {
|
||||
if (once && quashes) {
|
||||
once = false;
|
||||
quashes[requestors_length + index]
|
||||
= null;
|
||||
if (failure === undefined) {
|
||||
results[requestors_length + index]
|
||||
= success;
|
||||
optionals_successes += 1;
|
||||
}
|
||||
optionals_remaining -= 1;
|
||||
if (optionals_remaining === 0) {
|
||||
if (requestors_remaining === 0) {
|
||||
return requestors_length > 0 ||
|
||||
optionals_successes > 0
|
||||
? finish(results)
|
||||
: quash(failure);
|
||||
}
|
||||
if (timeout_till) {
|
||||
clearTimeout(timeout_till);
|
||||
timeout_till = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
initial
|
||||
);
|
||||
if (quashes[requestors_length + index] ===
|
||||
undefined) {
|
||||
quashes[requestors_length + index] = cancel;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
return quash;
|
||||
};
|
||||
},
|
||||
race: function race(requestors, milliseconds) {
|
||||
|
||||
// RQ.race takes an array of requestor functions. It starts them all
|
||||
// immediately. The first to finish wins. A race is successful if any
|
||||
// contestant is successful. It fails if all requestors fail or if the time
|
||||
// expires.
|
||||
|
||||
check("RQ.race", requestors, milliseconds);
|
||||
return function requestor(requestion, initial) {
|
||||
var quashes = [],
|
||||
remaining = requestors.length,
|
||||
timeout_id;
|
||||
|
||||
function finish(success, failure) {
|
||||
var r = requestion;
|
||||
if (r) {
|
||||
requestion = null;
|
||||
if (timeout_id) {
|
||||
clearTimeout(timeout_id);
|
||||
}
|
||||
quashes.forEach(function stop(quash) {
|
||||
if (typeof quash === 'function') {
|
||||
return setImmediate(quash);
|
||||
}
|
||||
});
|
||||
quashes = null;
|
||||
return r(success, failure);
|
||||
}
|
||||
}
|
||||
|
||||
function quash(reason) {
|
||||
return finish(undefined, reason || true);
|
||||
}
|
||||
|
||||
check_requestion("RQ.race", requestion, initial);
|
||||
if (milliseconds) {
|
||||
timeout_id = setTimeout(function timeout_id() {
|
||||
return quash(expired("RQ.race", milliseconds));
|
||||
}, milliseconds);
|
||||
}
|
||||
requestors.forEach(function (requestor, index) {
|
||||
return setImmediate(function () {
|
||||
var once = true, cancel = requestor(
|
||||
function requestion(success, failure) {
|
||||
if (once && quashes) {
|
||||
once = false;
|
||||
quashes[index] = null;
|
||||
if (failure === undefined) {
|
||||
return finish(success);
|
||||
}
|
||||
remaining -= 1;
|
||||
if (remaining === 0) {
|
||||
return quash(failure);
|
||||
}
|
||||
}
|
||||
},
|
||||
initial
|
||||
);
|
||||
if (quashes[index] === undefined) {
|
||||
quashes[index] = cancel;
|
||||
}
|
||||
});
|
||||
});
|
||||
return quash;
|
||||
};
|
||||
},
|
||||
sequence: function sequence(requestors, milliseconds) {
|
||||
|
||||
// RQ.sequence takes an array of requestor functions, and returns a requestor
|
||||
// that will call them each in order. An initial value is passed to each, which
|
||||
// is the previous success result.
|
||||
|
||||
// If any of the requestor functions fail, then the whole sequence fails, and
|
||||
// the remaining requestors are not called.
|
||||
|
||||
check("RQ.sequence", requestors, milliseconds);
|
||||
return function requestor(requestion, initial) {
|
||||
var cancel,
|
||||
timeout_id;
|
||||
|
||||
function finish(success, failure) {
|
||||
var r = requestion;
|
||||
cancel = null;
|
||||
if (r) {
|
||||
if (timeout_id) {
|
||||
clearTimeout(timeout_id);
|
||||
}
|
||||
requestion = null;
|
||||
return r(success, failure);
|
||||
}
|
||||
}
|
||||
|
||||
function quash(reason) {
|
||||
if (requestion && typeof cancel === 'function') {
|
||||
setImmediate(cancel, reason);
|
||||
}
|
||||
return finish(undefined, reason || true);
|
||||
}
|
||||
|
||||
check_requestion("RQ.sequence", requestion, initial);
|
||||
if (milliseconds) {
|
||||
timeout_id = setTimeout(function () {
|
||||
timeout_id = null;
|
||||
return quash(expired("RQ.sequence", milliseconds));
|
||||
}, milliseconds);
|
||||
}
|
||||
(function next(index) {
|
||||
var requestor, r = requestion;
|
||||
if (typeof r === 'function') {
|
||||
|
||||
// If there are no more requestors, then signal success.
|
||||
|
||||
if (index >= requestors.length) {
|
||||
if (timeout_id) {
|
||||
clearTimeout(timeout_id);
|
||||
}
|
||||
requestion = null;
|
||||
cancel = null;
|
||||
return r(initial);
|
||||
}
|
||||
|
||||
// If there is another requestor, call it in the next turn, passing the value
|
||||
// and a requestion that will take the next step.
|
||||
|
||||
requestor = requestors[index];
|
||||
setImmediate(function () {
|
||||
var once = true;
|
||||
cancel = requestor(
|
||||
function requestion(success, failure) {
|
||||
if (once) {
|
||||
once = false;
|
||||
cancel = null;
|
||||
if (failure !== undefined) {
|
||||
return quash(failure);
|
||||
}
|
||||
initial = success;
|
||||
return next(index + 1);
|
||||
}
|
||||
},
|
||||
initial
|
||||
);
|
||||
});
|
||||
}
|
||||
}(0));
|
||||
return quash;
|
||||
};
|
||||
}
|
||||
};
|
||||
}());
|
||||
Vendored
-218
@@ -1,218 +0,0 @@
|
||||
(function (global, undefined) {
|
||||
"use strict";
|
||||
|
||||
var tasks = (function () {
|
||||
function Task(handler, args) {
|
||||
this.handler = handler;
|
||||
this.args = args;
|
||||
}
|
||||
Task.prototype.run = function () {
|
||||
// See steps in section 5 of the spec.
|
||||
if (typeof this.handler === "function") {
|
||||
// Choice of `thisArg` is not in the setImmediate spec; `undefined` is in the setTimeout spec though:
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html
|
||||
this.handler.apply(undefined, this.args);
|
||||
} else {
|
||||
var scriptSource = "" + this.handler;
|
||||
/*jshint evil: true */
|
||||
eval(scriptSource);
|
||||
}
|
||||
};
|
||||
|
||||
var nextHandle = 1; // Spec says greater than zero
|
||||
var tasksByHandle = {};
|
||||
var currentlyRunningATask = false;
|
||||
|
||||
return {
|
||||
addFromSetImmediateArguments: function (args) {
|
||||
var handler = args[0];
|
||||
var argsToHandle = Array.prototype.slice.call(args, 1);
|
||||
var task = new Task(handler, argsToHandle);
|
||||
|
||||
var thisHandle = nextHandle++;
|
||||
tasksByHandle[thisHandle] = task;
|
||||
return thisHandle;
|
||||
},
|
||||
runIfPresent: function (handle) {
|
||||
// From the spec: "Wait until any invocations of this algorithm started before this one have completed."
|
||||
// So if we're currently running a task, we'll need to delay this invocation.
|
||||
if (!currentlyRunningATask) {
|
||||
var task = tasksByHandle[handle];
|
||||
if (task) {
|
||||
currentlyRunningATask = true;
|
||||
try {
|
||||
task.run();
|
||||
} finally {
|
||||
delete tasksByHandle[handle];
|
||||
currentlyRunningATask = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a
|
||||
// "too much recursion" error.
|
||||
global.setTimeout(function () {
|
||||
tasks.runIfPresent(handle);
|
||||
}, 0);
|
||||
}
|
||||
},
|
||||
remove: function (handle) {
|
||||
delete tasksByHandle[handle];
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
||||
function canUseNextTick() {
|
||||
// Don't get fooled by e.g. browserify environments.
|
||||
return typeof process === "object" &&
|
||||
Object.prototype.toString.call(process) === "[object process]";
|
||||
}
|
||||
|
||||
function canUseMessageChannel() {
|
||||
return !!global.MessageChannel;
|
||||
}
|
||||
|
||||
function canUsePostMessage() {
|
||||
// The test against `importScripts` prevents this implementation from being installed inside a web worker,
|
||||
// where `global.postMessage` means something completely different and can't be used for this purpose.
|
||||
|
||||
if (!global.postMessage || global.importScripts) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var postMessageIsAsynchronous = true;
|
||||
var oldOnMessage = global.onmessage;
|
||||
global.onmessage = function () {
|
||||
postMessageIsAsynchronous = false;
|
||||
};
|
||||
global.postMessage("", "*");
|
||||
global.onmessage = oldOnMessage;
|
||||
|
||||
return postMessageIsAsynchronous;
|
||||
}
|
||||
|
||||
function canUseReadyStateChange() {
|
||||
return "document" in global && "onreadystatechange" in global.document.createElement("script");
|
||||
}
|
||||
|
||||
function installNextTickImplementation(attachTo) {
|
||||
attachTo.setImmediate = function () {
|
||||
var handle = tasks.addFromSetImmediateArguments(arguments);
|
||||
|
||||
process.nextTick(function () {
|
||||
tasks.runIfPresent(handle);
|
||||
});
|
||||
|
||||
return handle;
|
||||
};
|
||||
}
|
||||
|
||||
function installMessageChannelImplementation(attachTo) {
|
||||
var channel = new global.MessageChannel();
|
||||
channel.port1.onmessage = function (event) {
|
||||
var handle = event.data;
|
||||
tasks.runIfPresent(handle);
|
||||
};
|
||||
attachTo.setImmediate = function () {
|
||||
var handle = tasks.addFromSetImmediateArguments(arguments);
|
||||
|
||||
channel.port2.postMessage(handle);
|
||||
|
||||
return handle;
|
||||
};
|
||||
}
|
||||
|
||||
function installPostMessageImplementation(attachTo) {
|
||||
// Installs an event handler on `global` for the `message` event: see
|
||||
// * https://developer.mozilla.org/en/DOM/window.postMessage
|
||||
// * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
|
||||
|
||||
var MESSAGE_PREFIX = "com.bn.NobleJS.setImmediate" + Math.random();
|
||||
|
||||
function isStringAndStartsWith(string, putativeStart) {
|
||||
return typeof string === "string" && string.substring(0, putativeStart.length) === putativeStart;
|
||||
}
|
||||
|
||||
function onGlobalMessage(event) {
|
||||
// This will catch all incoming messages (even from other windows!), so we need to try reasonably hard to
|
||||
// avoid letting anyone else trick us into firing off. We test the origin is still this window, and that a
|
||||
// (randomly generated) unpredictable identifying prefix is present.
|
||||
if (event.source === global && isStringAndStartsWith(event.data, MESSAGE_PREFIX)) {
|
||||
var handle = event.data.substring(MESSAGE_PREFIX.length);
|
||||
tasks.runIfPresent(handle);
|
||||
}
|
||||
}
|
||||
if (global.addEventListener) {
|
||||
global.addEventListener("message", onGlobalMessage, false);
|
||||
} else {
|
||||
global.attachEvent("onmessage", onGlobalMessage);
|
||||
}
|
||||
|
||||
attachTo.setImmediate = function () {
|
||||
var handle = tasks.addFromSetImmediateArguments(arguments);
|
||||
|
||||
// Make `global` post a message to itself with the handle and identifying prefix, thus asynchronously
|
||||
// invoking our onGlobalMessage listener above.
|
||||
global.postMessage(MESSAGE_PREFIX + handle, "*");
|
||||
|
||||
return handle;
|
||||
};
|
||||
}
|
||||
|
||||
function installReadyStateChangeImplementation(attachTo) {
|
||||
attachTo.setImmediate = function () {
|
||||
var handle = tasks.addFromSetImmediateArguments(arguments);
|
||||
|
||||
// Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
|
||||
// into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
|
||||
var scriptEl = global.document.createElement("script");
|
||||
scriptEl.onreadystatechange = function () {
|
||||
tasks.runIfPresent(handle);
|
||||
|
||||
scriptEl.onreadystatechange = null;
|
||||
scriptEl.parentNode.removeChild(scriptEl);
|
||||
scriptEl = null;
|
||||
};
|
||||
global.document.documentElement.appendChild(scriptEl);
|
||||
|
||||
return handle;
|
||||
};
|
||||
}
|
||||
|
||||
function installSetTimeoutImplementation(attachTo) {
|
||||
attachTo.setImmediate = function () {
|
||||
var handle = tasks.addFromSetImmediateArguments(arguments);
|
||||
|
||||
global.setTimeout(function () {
|
||||
tasks.runIfPresent(handle);
|
||||
}, 0);
|
||||
|
||||
return handle;
|
||||
};
|
||||
}
|
||||
|
||||
if (!global.setImmediate) {
|
||||
// If supported, we should attach to the prototype of global, since that is where setTimeout et al. live.
|
||||
var attachTo = typeof Object.getPrototypeOf === "function" && "setTimeout" in Object.getPrototypeOf(global) ?
|
||||
Object.getPrototypeOf(global)
|
||||
: global;
|
||||
|
||||
if (canUseNextTick()) {
|
||||
// For Node.js before 0.9
|
||||
installNextTickImplementation(attachTo);
|
||||
} else if (canUsePostMessage()) {
|
||||
// For non-IE10 modern browsers
|
||||
installPostMessageImplementation(attachTo);
|
||||
} else if (canUseMessageChannel()) {
|
||||
// For web workers, where supported
|
||||
installMessageChannelImplementation(attachTo);
|
||||
} else if (canUseReadyStateChange()) {
|
||||
// For IE 6–8
|
||||
installReadyStateChangeImplementation(attachTo);
|
||||
} else {
|
||||
// For older browsers
|
||||
installSetTimeoutImplementation(attachTo);
|
||||
}
|
||||
|
||||
attachTo.clearImmediate = tasks.remove;
|
||||
}
|
||||
}(typeof global === "object" && global ? global : this));
|
||||
Reference in New Issue
Block a user