2012-04-25 3 views
1

Я пытаюсь разработать класс в JavaScript. Я могу легко получить доступ к загрузке данных, собранных по запросу AJAX. Единственная проблема - мне нужно, чтобы члены класса были доступны только после завершения вызова AJAX. В идеале я хотел бы, чтобы в конечном итоге что-то, где с помощью я могу назвать это в скрипте:Выполнение функций до тех пор, пока вызов AJAX не будет завершен с помощью jQuery

courses.getCourse('xyz').complete = function() { 
    // do something with the code 
} 

И это будет только огонь после вызова AJAX была завершена и структуры данных в «классе» готовы быть использованным. В идеале я не хочу, чтобы создать .complete элемент для каждой функции в классе

Вот «класс» Я пытаюсь сделать так далеко:

var model_courses = (function() { 

    var cls = function() { 

     var _storage = {}; // Used for storing course related info 
     _storage.courses = {}; // Used for accessing courses directly 
     _storage.references = new Array(); // Stores all available course IDs 

     var _ready = 0; 
     $.ajax({ 
      type: "GET", 
      url: "data/courses.xml", 
      dataType: "xml", 
      success: function(xml) { 
       $(xml).find("course").each(function() { 

        _storage.courses[$(this).attr('id')] = { 
         title  : $(this).find('title').text(), 
         description : $(this).find('description').text(), 
         points  : $(this).find('points').text() 
        } 
        _storage.references.push($(this).attr('id')) 

       }) 

      } 
     }) 

     console.log(_storage.courses) 

    } 
    cls.prototype = { 
      getCourse: function (courseID) { 
       console.log(cls._storage) 
      }, 
      getCourses: function() { 
       return _storage.courses 
      }, 
      getReferences: function(), 
       return _storage.references 
      } 

    } 
    return cls 
})() 

В настоящее время getCourse будет уволен до того, как запрос AJAX будет завершен и, очевидно, у него не будет доступа к данным.

Любые идеи будут признательны, я застрял на этом!

+0

называет 'courses.getCourse ('хуг', функция (курс) {...})' недопустимо? Это стандартный способ работы с асинхронными операциями. –

ответ

1

Следующие изменения позволяют сделать запрос AJAX только один раз, и вы можете вызвать вашу функцию как

courses.getCourse('xyz', function(course){ 
    // Use course here 
}); 

Вот изменения

var model_courses = (function() { 

    // This is what gets returned by the $.ajax call 
    var xhr; 
    var _storage = {}; // Used for storing course related info 
    _storage.courses = {}; // Used for accessing courses directly 
    _storage.references = []; // Stores all available course IDs 

    var cls = function() { 
     xhr = $.ajax({ 
      type: "GET", 
      url: "data/courses.xml", 
      dataType: "xml", 
      success: function(xml) { 
       $(xml).find("course").each(function() { 

        _storage.courses[$(this).attr('id')] = { 
         title  : $(this).find('title').text(), 
         description : $(this).find('description').text(), 
         points  : $(this).find('points').text() 
        } 
        _storage.references.push($(this).attr('id')) 

       }); 
      } 
     }); 
    } 
    cls.prototype = { 
      // Made changes here, you'd have to make the same 
      // changes to getCourses and getReferences 
      getCourse: function (courseID, callback) { 
       if (xhr.readyState == 4) { 
        callback(_storage.courses[courseID]); 
       } 
       else { 
        xhr.done(function(){ 
         callback(_storage.courses[courseID]); 
        }) 
       } 

      }, 
      getCourses: function() { 
       return _storage.courses 
      }, 
      getReferences: function(), 
       return _storage.references 
      } 

    } 
    return cls 
})() 

В качестве побочного примечания ваш шаблон модуля не будет работать очень хорошо, если вам нужно создать два из этих объектов model_courses, поскольку объекты хранилища все разделены при закрытии вашей самозанятости. Обычно вы не смешиваете шаблон модуля с прототипами (возвращая конструктор из модуля), если вы действительно не знаете, что делаете, то есть общие переменные замыкания работают как статические свойства вашего класса .

Это то, что я хотел бы сделать, если бы я тебя (так как вы действительно хотите приватные переменные)

function ModelCourses() { 
    var storage = { 
     courses: {}, 
     references: [] 
    }; 

    var xhr = $.ajax({ 
     type: "GET", 
     url: "data/courses.xml", 
     dataType: "xml", 
     success: function(xml) { 
      $(xml).find("course").each(function() { 
       storage.courses[$(this).attr('id')] = { 
        title  : $(this).find('title').text(), 
        description : $(this).find('description').text(), 
        points  : $(this).find('points').text() 
       } 
       storage.references.push($(this).attr('id')) 
      })  
     } 
    }); 

    this.getCourse = function(courseId, callback) { 
     function getCourse() { 
      callback(storage.courses[courseID]) 
     } 
     if (xhr.readyState == 4) { 
      getCourse(); 
     } 
     else { 
      xhr.done(getCourse); 
     } 
    }; 
} 
+0

Спасибо, Хуан, это то, что я искал. Поддержки к @Kevin B, я работал над чем-то очень похожим на это, используя свою помощь выше! –

3

jQuery уже обрабатывает это для вас, используя отложенные объекты, если я не понимаю, что вы ищете.

var courses = { 
    getCourse: function (id) { 
     return $.ajax({url:"getCourse.php",data:{id:id}); 
    } 
}; 

courses.getCourse("history").done(function(data){ 
    console.log(data); 
}); 

Я знаю, что это не совсем то, что вы ищете, я надеюсь, что этого достаточно, чтобы подтолкнуть вас в правильном направлении. Отложенные объекты являются удивительными.

+0

Это шаг в правильном направлении, единственное, что я сказал, id, чтобы уметь логически загружать данные один раз. В теории ид нужно что-то вроде курсов .__ init.done (функция() { cls.prototype = { }} Однако, как Christie @ Брэд упомянуто ниже, это будет выдавать ошибку, если скрипт пытается получить доступ к член до того, как данные станут доступными. –

+1

Правильно, не будет способа заставить код, пытающийся получить доступ к данным, ждать до тех пор, пока данные не будут готовы, если только он не использует обратный вызов какого-либо типа, например выполненный обратный вызов (даже если спрятанный за другим методом). Например, getCourse() всегда требует обратного вызова или возвращает отложенный объект, а не просто вывод данных. Если запрос ajax уже завершен, обратный вызов запускается немедленно. –

0

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

+0

Как я могу реализовать первый метод, в то время как keepin g скрипт async? Я не хочу, чтобы остальные скрипты на странице были задержаны для запроса AJAX выше, чтобы закончить, если это имеет смысл? –

0

Вы можете определить функцию getData, которая будет выполнять запрос ajax, и в качестве обратного вызова будет принимать getCourse. getData может локально локально получить результат вызова Ajax и протестировать локальное хранилище перед выполнением вызова ajax.

Вы также можете указать частный член, чтобы разрешить вызов ajax только один раз. Вы можете проверить underscore.js для некоторого удобного инструмента

Вот небольшой пример кода:

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