Обещание AJAX без данных Ember

Я решил не использовать данные ember-data, так как он не готов и все еще меняется. Мое приложение только должно сделать несколько аякс-запросов в любом случае, чтобы не было слишком большой разницы. У меня возникли проблемы с пониманием того, как обращаться с ответом на ajax-обещание.

Когда мой пользователь загружает приложение, у них уже есть сеанс с проверкой подлинности. Я пытаюсь выполнить ping-сервер для этой информации о пользователях и отобразить его в моем шаблоне. Кажется, мой шаблон отображается до того, как мой запрос ajax возвращает результаты, а затем не обновляется с обещанием.

// route
App.ApplicationRoute = Ember.Route.extend({
    setupController: function(){
        this.set("currentUser", App.User.getCurrentUser());
    }
});


// model
App.User = Ember.Object.extend({
    email_address: '',
    name_first: '',
    name_last: '',
    name_full: function() {
        return this.get('name_first') + ' ' + this.get('name_last');
    }.property('name_first', 'name_last')
});
App.User.reopenClass({
    getCurrentUser: function() {
        return $.ajax({
            url: "/api/get_current_user",
            type: "POST",
            data: JSON.stringify({})
        }).then(function(response) {
            return response;
        });
    }
});

В моем шаблоне:

<h1> Hey, {{App.currentUser.name_first}}</h1>

Как я могу обновить шаблон, когда получаю ответ или задержку, пока у меня не будет ответа?

Ответы

Ответ 1

На самом деле ответ довольно прост: вам не нужно использовать обещание. Вместо этого просто верните пустой объект. Ваш код может выглядеть так:

App.User.reopenClass({
    getCurrentUser: function() {
        var user = App.User.create({}); //create an empty object
        $.ajax({
            url: "/api/get_current_user",
            type: "POST",
            data: JSON.stringify({})
        }).then(function(response) {
            user.setProperties(response); //fill the object with your JSON response
        });
        return user;
    }
});

Что здесь происходит?

  • Вы создаете пустой объект.
  • Вы выполняете асинхронный вызов вашего API...
  • ... и в вашем обратном вызове успеха вы заполняете пустой объект.
  • Вы возвращаете свой пользовательский объект.

Примечание. Что происходит на самом деле? Поток, упомянутый выше, не является последовательностью, в которой эти действия происходят. На самом деле сначала выполняются точки 1,2 и 4. Затем через некоторое время, когда ответ вернется с вашего сервера, выполняется 3. Итак, реальный поток действий: 1 → 2 → 4 → 3.

Таким образом, общее правило состоит в том, чтобы всегда возвращать объект, который позволяет Ember выполнять свою логику. Никакие значения не будут отображаться сначала в вашем случае, и как только ваш объект будет заполнен. Ember начнет делать свою магию и автоматическое обновление ваших шаблонов. Никакой тяжелой работы не должно быть сделано на вашей стороне!


Исходя из первоначального вопроса: как это сделать с массивом? Следуя этому общему правилу, вы должны вернуть пустой массив. Вот небольшой пример, который предполагает, что вы можете захотеть получить всех пользователей от вашего бэкэнда:

App.User.reopenClass({
    getAllUsers: function() {
        var users = []; //create an empty array
        $.ajax({
            url: "/api/get_users",
        }).then(function(response) {
            response.forEach(function(user){
                var model = App.User.create(user); 
                users.addObject(model); //fill your array step by step
            });
        });
        return users;
    }
});

Ответ 2

Я бы использовал Ember.Deferred вместо того, чтобы возвращать пустой массив, как упоминалось ранее.

App.User.reopenClass({
  getAllUsers: function() {
    var dfd = Ember.Deferred.create();
    var users = [];

    $.ajax({
        url: "/api/get_users",
    }).then(function(response) {
        response.forEach(function(user){
            var model = App.User.create(user); 
            users.addObject(model);
        });
        dfd.resolve(users);
    });
    return dfd;
  }
});

В вашей модели все, что вам нужно сделать, это

model: function(){
  return App.User.getAllUsers();
}

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

Ответ 3

Вы также можете установить текущего пользователя в качестве модели для ApplicationRoute следующим образом:

App.ApplicationRoute = Ember.Route.extend({
    model: function() {
        return App.User.getCurrentUser();
    }
});

Так как getCurrentUser() возвращает обещание, переход приостанавливается до тех пор, пока обещание не выполнит или не отклонит.

Это удобно, потому что по завершению перехода времени ваша модель инициализируется, и вы увидите ее в шаблоне.

Вы можете читать больше об асинхронной маршрутизации в руководствах Ember.