Как использовать, когда затем отправлять загрузку файлов последовательно в функции, которая также является отложенным обещанием?

StackOverflow https://stackoverflow.com//questions/23065705

Вопрос

Я собираюсь загрузить массив файлов с помощью jQuery.

Это намерение заключено в функцию под названием uploadFilesUsingAjax();

var uploadFilesPromise = uploadFilesUsingAjax();

$.when(uploadFilesPromise).done(function (uploadFilesAjaxResult) {
        // redirect to success page...

Мне нужно дождаться успешной загрузки всех файлов, прежде чем делать что-то еще.

Внутри uploadFilesUsingAjax(),

Я написал свой код таким образом

function uploadFilesUsingAjax() {
    var files = pages; // pages is a global variable which is an array of files
    var url = "/users/" + currentUser.id + "/files.json";
    var type = "POST";

    console.info('files length:' + files.length);
    if (files.length > 0) {

        var promises=[];
        for (var i = 0; i < files.length; i++) {
            var data = new FormData();
            var postData = {};
            var file = files.getByIndex(i);
            var key = i + 1;
            if (typeof (file.id) !== "undefined" && file.id > 0) {
                data.append(key, JSON.stringify(file));
            } else {
                data.append(key, file);
            }
            var request = $.ajax({
                //this is the php file that processes the data 
                url: url,

                //POST method is used
                type: type,

                //pass the data
                data: data,

                //Do not cache the page
                cache: false,

                xhr: function() {
                    // custom xhr
                    myXhr = $.ajaxSettings.xhr();
                    if(myXhr.upload) { // check if upload property exists

                            myXhr.upload.addEventListener('progress',updatePagesProgress, false); // for handling the progress of the upload
                    }
                    return myXhr;
                },

                // DO NOT set the contentType and processData
                // see http://stackoverflow.com/a/5976031/80353
                contentType: false,
                processData: false,

                //success
                success: function (json) {
                    // json is already an object thanks to cakephp code to serialize

                    //if POST is a success expect no errors
                    if (json.error == null && json.result != null) {
                        currentUser = json.result.User;
                    // error
                    } else {
                        alert(json.error);
                    }
                }
            });
            promises.push( request);
        }

        var promise = promises[0];
        for (var i = 1; i < promises.length; i++) {
          promise = promise.then(promises[i]);
        }

        return promise.done(function () { console.log('all!')});

К сожалению, мне не удалось загрузить много файлов, прежде чем меня перенаправили на страницу успеха.

Я пробовал различные решения StackOverflow, как это сделать.Пока ничего не работает.Пожалуйста, порекомендуйте.

Некоторый код был урезан для экономии места.

Это было полезно?

Решение

Все ваши обещания параллельны, а не последовательны.

Обещание представляет собой уже работает задача.Промисы в JavaScript, в отличие от задач C# или других абстракций, уже запускаются.Способ представления задачи, которая еще не началась, — это функция, возвращающая обещание.

С promises[i] это уже обещание - когда ты это сделаешь promise.then(object) он не добавляет обработчик .then, а возвращает немедленно. .then игнорирует любые аргументы, которые не являются функцией.

Вот почему он возвращается раньше, он возвращается, как только будет выполнено первое обещание.Вам также не понадобится .when.Создайте функцию, которая создает процесс загрузки как таковой:

function createUploadTask(file,i){
    return function(){
         var data = new FormData();
         var postData = {};
         var file = files.getByIndex(i);
         var key = i + 1;
         if (typeof (file.id) !== "undefined" && file.id > 0) {
             data.append(key, JSON.stringify(file));
         } else {
             data.append(key, file);
         }
         return $.ajax({...}); // return the promise
   }
}

Теперь вы можете сопоставить файлы с задачами:

 var tasks = files.map(createUploadTask);

Обратите внимание, что теперь задания каждая функции которые возвращают обещание при загрузке файла.Это не обещания.

Теперь вы можете объединить их:

 var p = tasks[0](); // start off the chain
 for(var i = 1; i < tasks.length; i++){
      // chain the next task, note, that we're passing a _function_ here
      // when you return a promise from a `.then` it will fulfill when that promise 
      // fulfills, in our case the $.ajax
      p = p.then(tasks[i]); 
 }
 return p;

Вам также теперь не нужно использовать When, поскольку вы возвращаете одинокий обещать.Я предполагаю, что вам здесь не нужен фактический результат (а только для того, чтобы узнать успех/неуспех).

Вы просто делаете:

 function uploadFilesUsingAjax() {
     // settings
     if(tasks.length === 0){
          // a method MUST always either return either synchronously or asynchronously never
          // both, always return a promise. Otherwise you get API hell.
          var d = $.Deferred();
          d.reject(new Error("Called uploadFiles with no files to upload"));
          return d.promise;
     }
     tasks = pages.map(createUploadTask)
     var p = tasks[0](); // call first one
     for(var i = 1; i < tasks.length; i++) p = p.then(tasks[i]);
     return p; 
 }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top