كيف يتم استخدام متى ثم لإرسال تحميل الملف بشكل تسلسلي في وظيفة تعد أيضًا وعدًا مؤجلًا؟

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;

أنت أيضًا لا تحتاج الآن إلى استخدام متى، نظرًا لأنك تقوم بإرجاع ملف أعزب يعد.أفترض أنك لا تحتاج إلى النتيجة الفعلية هنا (ولكن فقط لمعرفة النجاح/الفشل).

أنت ببساطة تفعل:

 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