Некоторые посты показали, как отображать прогресс команды. Чтобы рассчитать это, вам нужно увидеть, насколько вы продвинулись. В системах BSD некоторые команды, такие как dd (1), принимают сигнал SIGINFO
и сообщают о своем прогрессе. В системах Linux некоторые команды будут реагировать аналогично SIGUSR1
. Если эта возможность доступна, вы можете направить свой ввод через dd
, чтобы отслеживать количество обработанных байтов.
В качестве альтернативы, вы можете использовать lsof
, чтобы получить смещение указателя чтения файла и, таким образом, рассчитать прогресс. Я написал команду с именем pmonitor , которая отображает ход обработки указанного процесса или файла. С его помощью вы можете делать такие вещи, как следующие.
$ pmonitor -c gzip
/home/dds/data/mysql-2015-04-01.sql.gz 58.06%
Более ранняя версия сценариев оболочки Linux и FreeBSD появилась в моем блоге .
Попробуйте это решение, которое может поддерживать любое количество параллельных запросов:
var done = 4; // number of total requests
var sum = 0;
/* Normal loops don't create a new scope */
$([1,2,3,4,5]).each(function() {
var number = this;
$.getJSON("/values/" + number, function(data) {
sum += data.value;
done -= 1;
if(done == 0) $("#mynode").html(sum);
});
});
Вот моя попытка напрямую ответить на ваш вопрос
По сути, вы просто создаете стек вызовов AJAX, выполняете их все, и по завершении всех событий вызывается предоставленная функция - предоставленный аргумент является массивом результатов всех предоставленных запросов ajax.
Очевидно, что это ранний код - вы могли бы уточнить его с точки зрения гибкости.
<script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
var ParallelAjaxExecuter = function( onComplete )
{
this.requests = [];
this.results = [];
this.onComplete = onComplete;
}
ParallelAjaxExecuter.prototype.addRequest = function( method, url, data, format )
{
this.requests.push( {
"method" : method
, "url" : url
, "data" : data
, "format" : format
, "completed" : false
} )
}
ParallelAjaxExecuter.prototype.dispatchAll = function()
{
var self = this;
$.each( self.requests, function( i, request )
{
request.method( request.url, request.data, function( r )
{
return function( data )
{
console.log
r.completed = true;
self.results.push( data );
self.checkAndComplete();
}
}( request ) )
} )
}
ParallelAjaxExecuter.prototype.allRequestsCompleted = function()
{
var i = 0;
while ( request = this.requests[i++] )
{
if ( request.completed === false )
{
return false;
}
}
return true;
},
ParallelAjaxExecuter.prototype.checkAndComplete = function()
{
if ( this.allRequestsCompleted() )
{
this.onComplete( this.results );
}
}
var pe = new ParallelAjaxExecuter( function( results )
{
alert( eval( results.join( '+' ) ) );
} );
pe.addRequest( $.get, 'test.php', {n:1}, 'text' );
pe.addRequest( $.get, 'test.php', {n:2}, 'text' );
pe.addRequest( $.get, 'test.php', {n:3}, 'text' );
pe.addRequest( $.get, 'test.php', {n:4}, 'text' );
pe.dispatchAll();
</script>
здесь test.php
<?php
echo pow( $_GET['n'], 2 );
?>
вы можете сделать что-то вроде этого
var allData = []
$.getJSON("/values/1", function(data) {
allData.push(data);
if(data.length == 2){
processData(allData) // where process data processes all the data
}
});
$.getJSON("/values/2", function(data) {
allData.push(data);
if(data.length == 2){
processData(allData) // where process data processes all the data
}
});
var processData = function(data){
var sum = data[0] + data[1]
$('#mynode').html(sum);
}
Если результат одного запроса зависит от другого, вы не можете сделать их параллельными.
Обновление: Согласно ответу Яира Левиэля, этот ответ устарел. Используйте библиотеку обещаний, например jQuery.when () или Q.js.
Я создал решение общего назначения как расширение jQuery. Можно было бы использовать некоторую тонкую настройку, чтобы сделать его более общим, но это соответствовало моим потребностям. Преимущество этого метода перед другими в этой публикации на момент написания этой статьи состояло в том, что можно было использовать любой тип асинхронной обработки с обратным вызовом.
Примечание: я бы использовал расширения Rx для JavaScript вместо этого, если бы думал, что мой клиент не возражает против использования еще одной сторонней библиотеки :)
// jQuery extension for running multiple async methods in parallel
// and getting a callback with all results when all of them have completed.
//
// Each worker is a function that takes a callback as its only argument, and
// fires up an async process that calls this callback with its result.
//
// Example:
// $.parallel(
// function (callback) { $.get("form.htm", {}, callback, "html"); },
// function (callback) { $.post("data.aspx", {}, callback, "json"); },
// function (formHtml, dataJson) {
// // Handle success; each argument to this function is
// // the result of correlating ajax call above.
// }
// );
(function ($) {
$.parallel = function (anyNumberOfWorkers, allDoneCallback) {
var workers = [];
var workersCompleteCallback = null;
// To support any number of workers, use "arguments" variable to
// access function arguments rather than the names above.
var lastArgIndex = arguments.length - 1;
$.each(arguments, function (index) {
if (index == lastArgIndex) {
workersCompleteCallback = this;
} else {
workers.push({ fn: this, done: false, result: null });
}
});
// Short circuit this edge case
if (workers.length == 0) {
workersCompleteCallback();
return;
}
// Fire off each worker process, asking it to report back to onWorkerDone.
$.each(workers, function (workerIndex) {
var worker = this;
var callback = function () { onWorkerDone(worker, arguments); };
worker.fn(callback);
});
// Store results and update status as each item completes.
// The [0] on workerResultS below assumes the client only needs the first parameter
// passed into the return callback. This simplifies the handling in allDoneCallback,
// but may need to be removed if you need access to all parameters of the result.
// For example, $.post calls back with success(data, textStatus, XMLHttpRequest). If
// you need textStatus or XMLHttpRequest then pull off the [0] below.
function onWorkerDone(worker, workerResult) {
worker.done = true;
worker.result = workerResult[0]; // this is the [0] ref'd above.
var allResults = [];
for (var i = 0; i < workers.length; i++) {
if (!workers[i].done) return;
else allResults.push(workers[i].result);
}
workersCompleteCallback.apply(this, allResults);
}
};
})(jQuery);
ОБНОВЛЕНИЕ И еще два года спустя это выглядит безумным, потому что принятый ответ изменился на что-то намного лучшее! (Хотя все еще не так хорошо, как ответ Яира Левиэля с использованием jQuery , когда
)
18 месяцев спустя я просто наткнулся на нечто подобное. У меня есть кнопка обновления, и я хочу, чтобы старый контент был fadeOut
, а новый контент - fadeIn
. Но мне также нужно получить
новый контент. fadeOut
и get
являются асинхронными, но запускать их поочередно было бы пустой тратой времени.
То, что я делаю, действительно совпадает с принятым ответом, за исключением формы многоразовой функции. Его главное достоинство в том, что он намного короче, чем другие предлагаемые здесь.
var parallel = function(actions, finished) {
finishedCount = 0;
var results = [];
$.each(actions, function(i, action) {
action(function(result) {
results[i] = result;
finishedCount++;
if (finishedCount == actions.length) {
finished(results);
}
});
});
};
Вы передаете ему массив функций для параллельного выполнения. Каждая функция должна принимать другую функцию, которой она передает свой результат (если есть). Эту функцию будет выполнять parallel
.
Вы также передаете ему функцию, которая будет вызываться после завершения всех операций. Он получит массив со всеми результатами. Итак, мой пример:
refreshButton.click(function() {
parallel([
function(f) {
contentDiv.fadeOut(f);
},
function(f) {
portlet.content(f);
},
],
function(results) {
contentDiv.children().remove();
contentDiv.append(results[1]);
contentDiv.fadeIn();
});
});
Итак, когда моя кнопка обновления нажата, я запускаю эффект jQuery fadeOut
, а также свой собственный портлет .content
(которая выполняет async get
, создает новый бит контента и передает его), а затем, когда оба они завершены, я удаляю старый контент, добавляю результат второй функции ( который находится в результатах [1]
) и fadeIn
новый контент.
Поскольку fadeOut
ничего не передает своей функции завершения, results [0]
предположительно содержит undefined
, поэтому я игнорирую его. Но если бы у вас было три операции с полезными результатами, они бы поместили каждый слот в массив results
в том же порядке, в котором вы передали функции.