2013-05-24 5 views
5

У меня есть форма AJAX, где пользователи могут загружать файлы CSV. Эти файлы довольно малы, и обработка на стороне сервера займет гораздо больше времени, чем фактическая загрузка файла. Тем не менее, загрузка может по-прежнему занимать секунду или два, в зависимости от размера файла и скорости соединения. Кроме того, важно, чтобы пользователь знал, что операция на стороне сервера выполнена успешно или не удалась.Определите, был ли AJAX-запрос завершен, все еще ожидая ответа

Теперь я хотел бы различать «загрузку файла» и «ожидание ответа», поэтому я могу показать соответствующие значки сообщений/индикаторов и т. Д. Пользователю.

Я использую jQuery's $.ajax, где я могу указать номер complete(). Но это не срабатывает, пока не будет получен ответ сервера. И насколько я могу судить, нет requestComplete() -callback.

Итак, можно ли определить, был ли полностью отправлен запрос AJAX на сервер, хотя сервер еще не ответил?

Я бы предпочел не прибегать к асинхронной обработке на сервере и нажимать на клиента (WebSockets или Comet и т. Д.), Если это возможно. (Сервер запускает PHP).

ответ

2

В соответствии с требованиями your comment, приведено более полное описание my comment.

Что касается отслеживания загрузки, это возможно без необходимости писать определенный серверный код для поддержки отслеживания загрузки. Как вы уже упоминали, я говорил о onprogress event provided by XMLHttpRequest level 2. Он довольно прост в использовании.Обратите внимание на небольшой участок ссылке, которую я только что говорил:

var oReq = new XMLHttpRequest(); 

oReq.addEventListener("progress", updateProgress, false); 

oReq.open(); 

oReq.send(something); 

// progress on transfers from the server to the client (downloads) 
function updateProgress (oEvent) { 
    if (oEvent.lengthComputable) { 
    var percentComplete = oEvent.loaded/oEvent.total; 
    // ... 
    } else { 
    // Unable to compute progress information since the total size is unknown 
    } 
} 

Как другой пункт упоминается в вашем вопросе:

Я хотел бы провести различие между «Загрузка файла» и " ожидая ответа ", поэтому я могу показать соответствующие сообщения/индикаторы и т. д. пользователю.

Это, безусловно, возможно в теории. Что я делаю в библиотеке загрузки кросс-браузера, которую я поддерживаю, Fine Uploader, ждет, пока последний байт не будет отправлен (в соответствии с моим обработчиком хода), а затем добавьте сообщение рядом с файлом в пользовательском интерфейсе, например «обработка». . ". Я предположил, что по мере отправки последнего байта сервер выполняет некоторые задачи в файле, и теперь я просто жду ответа.

Я сказал, что это можно обнаружить теоретически, но не на практике кросс-браузер. Зачем? Я прокомментировал это в a case in the Fine Uploader Github repository. Я буду включать полноту мой комментарий здесь:

Я заметил, что Firefox не срабатывает его последнее событие прогресса, пока не получает ответ от сервера, который является немного лентяй. Существует Firefox issue, поданный для отслеживания этой «проблемы».

Похоже, что Firefox действительно может следовать букве спецификации XHR V2, в то время как Chrome придерживается «духа» спецификации. Выполнение Chrome, которое приводит к последнему событию прогресса , выпущенному после последнего байта, было «отправлено», что больше всего может ожидать, но это может быть просто нарушением спецификации. Не уверен, что IE10 еще не , поскольку я еще не изучал это. Разработчик FF открыл нить на странице w3.org с просьбой о некоторых разъяснениях.

Chromium dev считает, что «ожидаемое» поведение на самом деле является webkit , а не для Chrome. Это говорит о том, что Safari и Chrome имеют такое же поведение, которое я проверил. Звучит , так как есть толчок для настройки спецификации, чтобы поведение вебкита до было ожидаемым поведением (согласно букве спецификации).

Обратите внимание, что я не использую событие «loadend», чтобы определить, когда браузер закончил отправку последнего байта. Я просто сравниваю «загруженное» значение с «общим» значением при обработке событий «прогресс» . Если эти два значения равны, я объявляю файл «полностью отправленным». Согласно спецификации, я должен был бы сделать это (я думаю), так как событие «loadend» просто запускается после последнего события «прогресс». См. Спецификацию относительно ProgressEvent для получения дополнительной информации о .

Подводя итог, это прекрасно работает в Chrome и Safari, но не в FireFox. Я не могу вспомнить, работает ли это в IE10 или нет. Я не могу вспомнить, так как я не очень много использую IE. В Firefox индикатор прогресса будет застревать, когда он достигнет около 99% или около того, пока не будет получен ответ.

Обратите внимание, что все это отслеживание прогресса возможно только в том случае, если пользовательский агент поддерживает API файлов. Это оставляет IE9 и старше.Для браузеров, не относящихся к файлу API, существует несколько вариантов:

  1. Установите какое-то соглашение, включающее запросы GET, которые понимают клиент и сервер. Клиент будет периодически отправлять запросы GET на сервер, и сервер должен будет реагировать на прогресс файла. FYI Fine Uploader имеет a scheduled feature request, чтобы посмотреть на это больше, хотя я не очень сумасшедший в этом подходе.
  2. Еще один вариант, который выглядит немного лучше, но, возможно, немного более ограниченным (поскольку он зависит от сервера приложений) заключается в использовании модуля UploadProgress в nginx (произносится как Engine-X, если вы не знакомы). Мне сказали, что у Apache есть аналогичный модуль, но я не смог найти какую-либо документацию для этого (хотя я вообще не рассматривал это вообще). У Fine Uploader также есть [запрос функции для этого (https://github.com/Widen/fine-uploader/issues/506), который я буду исследовать в ближайшем будущем.

Надеюсь, это ответит на ваши вопросы.

+0

Ничего себе, отличный ответ и подробное объяснение! Большое спасибо! IE9 и ниже не заботятся обо мне, но Firefox - слишком плохо, что он тоже не работает. К сожалению, я не могу согласиться с вашим ответом, хотя мне бы очень хотелось. Похоже, мне придется реализовать какое-то серверное решение. Тем не менее, большое спасибо за ваш ответ! –

+0

Мой ответ включает это как резерв. Что здесь отсутствует? –

+0

Вы правы, но ответ arnaud упоминает технологию, непосредственно относящуюся к моей серверной среде (функция отслеживания загрузки PHP), которой у вас нет. Хотя после прочтения модуля Apache UploadProgress, который вы упомянули, я решил использовать его вместо этого. Итак, вот вы идите, ответьте на прием! –

4

См. Функцию Session Upload Progress.

Когда включено, PHP будет хранить информацию о ходе выполнения загрузки в сеансе пользователя. Затем вы можете извлечь эти данные, выполнив несколько ajax pulling.

В качестве альтернативы, APC имеет номер similar feature.

+0

Похож на потенциальный способ сделать это, спасибо. Хотя я все еще надеюсь, что может быть только клиентское решение ... –

+0

Он не может быть полностью на стороне клиента, сервер должен что-то сигнализировать каким-то образом :). Один из способов сообщить, что загрузка завершена, может чтобы вызвать flush(), чтобы заставить php отправлять заголовки http раньше. Если клиент может это увидеть (может быть, xhr.readystate изменяет?), Этого может быть достаточно. – arnaud576875

+1

Существует только клиентское решение, но оно не работает в IE9 или старше. Подробности см. В спецификации XHR Level 2. –

2

Ответ на arnaud576875 применим к фактической загрузке файла (который, как вы говорите, может занимать или не принимать секунд). Вам могут потребоваться оба метода. В общем, в PHP нет механизма для отслеживания прогресса внутри скрипта - и PHP не знает, в каком% он находится, и не обязательно ли он возвращать какие-либо данные вызывающему до конца (даже если это так, ваш JS не получит частичный выход).

Стандартный способ сделать это - заставить браузер постоянно опросить сервер о ходе выполнения сценария. Загрузка является отдельной, поэтому вам также нужно будет найти это и объединить два числа - для этого потребуется оценка того, сколько времени потребуется каждая задача (загрузка, обработка) и некоторые хорошие навыки алгебры.

В вашем скрипте вам необходимо определить процент выполненного действия (если у вас есть большой цикл foreach, это легко) и сохранить его где-нибудь (база данных, файл, APC). Вам понадобится также способ идентификации пользователя (user_id и/или передать случайное число из javascript в качестве идентификатора).

Ваш сценарий опроса (например, каждые 2 секунды) получит этот номер для выполнения сценария путем передачи уникальных идентификаторов.

+0

Спасибо за ваш ответ, это некоторые хорошие моменты относительно прогресса на стороне сервера. Но в моем случае я заинтересован только в том, что передача данных завершена и начата обработка - на данный момент я не буду отслеживать прогресс на стороне сервера. –

Смежные вопросы