質問

The usual way of using jquery deferred.resolve method is by calling it when you have a callback function which gives you a response that they are fully loaded, as in this case the xhr add an event listener when it is loaded and provides the xhr response to deferred.resolve.

The following code is copied from one of the example. http://www.danieldemmel.me/blog/2013/03/22/an-introduction-to-jquery-deferred-slash-promise/

function getData(){      
  var deferred = $.Deferred();           
  XMLHttpRequest xhr = new XMLHttpRequest();
  xhr.open("GET","data",true);            
  xhr.addEventListener('load',function(){
    if(xhr.status === 200){          
      deferred.resolve(xhr.response);
    }else{          
      deferred.reject("HTTP error: " + xhr.status);
    }
  },false)             
  xhr.send();
  return deferred.promise();
}

My current code which retrieves data using Marionette request-response handler. Is there anyway i can get a callback response from the following request

function getData(activityID) {
  var defer = $.Deferred();
  require(["entities/element/element_collection"], function() {
    var fetchData = App.request("element:entities:initialize", activityID);
    //Example code scenario
    // How do i know my request is being fulfilled? and used Deferred.resolve accordingly.
    //maybe something as follows?
     fetchData.success(function(response){
        defer.resolve(response);
     }); 
     //Example code scenario 

  });

  return defer.promise();
};

The request handler basically will be giving back a Backbone collection which will be generated by passing a collection of objects into the new Backbone Collection.

役に立ちましたか?

解決

If (as it would appear) require() is asynchronous and App.request() is synchronous, then you could write your code as follows :

function getData(activityID) {
  var defer = $.Deferred();
  require(["entities/element/element_collection"], function() {
    var fetchData = App.request("element:entities:initialize", activityID);
    defer.resolve(fetchData);
  });
  return defer.promise();
};

getData(activityID).done(function(fetchData) {
    //do awesome stuff with fetchData here
});

or, depending on how much/little you want to do in getData(), as follows :

function getData() {
  var defer = $.Deferred();
  require(["entities/element/element_collection"], defer.resolve);
  return defer.promise();
};

getData().done(function() {
    var fetchData = App.request("element:entities:initialize", activityID);
    //do awesome stuff with fetchData here
});

However, if App.request() is also asynchronous, then it can't return data - it has to return a promise of data, and the code would be like this :

function getData(activityID) {
  var defer = $.Deferred();
  require(["entities/element/element_collection"], function() {
    App.request("element:entities:initialize", activityID).done(defer.resolve);
  });
  return defer.promise();
};

getData(activityID).done(function(fetchData) {
    //do awesome stuff with fetchData here
});

or :

function getData() {
  var defer = $.Deferred();
  require(["entities/element/element_collection"], defer.resolve);
  return defer.promise();
};

getData().done(function() {
    App.request("element:entities:initialize", activityID).done(function(fetchData) {
        //do awesome stuff with fetchData here
    });
});

If App.request() is asynchronous and neither returns a promise nor accepts a callback, then the person who wrote it needs to be spoken to. App.request() would need to be rewritten or you would need to find another utility to do the job.

他のヒント

Getting data from the server is by default an asynchronous call, so why wouldn't you use a command instead of request/response and listen to the model events? I think it would be easier. On this topic, I would create a channel that will provide,

  1. the command to fetch data
  2. the model or the collection instances the channel applies on.

and then the controller just has to subscribe to the channel to get the data and will listen to the collection instance events (sync error change, whatever basic backbone events on model/collection you want)

/* Constants: Simulation of API data. */
Constants = {};

Constants.jsonLanguages = [
    {Name: "English", Code: "en", isEditable:true},
    {Name: "French", Code: "fr", isEditable:false},
    {Name: "German", Code: "de", isEditable:true},
    {Name: "Spanish", Code: "es", isEditable:false}
];

Constants.jsonBook = {
    Title: "Dune",
    AuthorName: "Frank Herbert",
    LanguageCode: "en",
    ISBN: "978-1-4493-9268-0"
};



/* ----------------------------------------------------------------------------- */
/* Models */

// Language/Models.js
var models = {};
models.Language = Backbone.Model.extend({
    defaults: {
        Name: "English",
        Code: "en"
    },
    idAttribute:"Code",
    url: "/echo/json/"
});

models.LanguageCollection = Backbone.Collection.extend({
    model: models.Language,
    url: "/echo/json/"
});

// Book/Models.js
models.Book = Backbone.Model.extend({
    defaults: {
        Title: "",
        AuthorName: "",
        Language: null
    },
    url: "/echo/json/",
    idAttribute: "ISBN"
});



/* ----------------------------------------------------------------------------- */
/* Channels: Manage data between server and client. 
    - dependencies : wreqr, related models, related routes */
// Languages/Channel.js
var LanguageChannel = {};
LanguageChannel.data = {};
LanguageChannel.data.workingLanguage = new models.Language();
LanguageChannel.data.languages = new models.LanguageCollection();
LanguageChannel.channel = Backbone.Wreqr.radio.channel("Languages");
LanguageChannel.channel.commands.setHandler("getLanguages", function() {
    // here you typically fetch the data using backbone collection and backbone router
    window.console && console.log("LanguageChannel.channel.command.getLanguages()");
    LanguageChannel.data.languages.reset(Constants.jsonLanguages);
    LanguageChannel.data.languages.trigger("sync");
});

// Books/Channel.js
var BookChannel = {};
BookChannel.data = {};
BookChannel.data.book = new models.Book();
BookChannel.channel = Backbone.Wreqr.radio.channel("Books");
BookChannel.channel.commands.setHandler("getBook", function(id){
    // here you typically fetch the data using backbone model & backbone router
    window.console && console.log("BookChannel.channel.commands.getBook(" + id +")");
    BookChannel.data.book.set(Constants.jsonBook, {reset:true});
    BookChannel.data.book.trigger("sync");
});

/* ----------------------------------------------------------------------------- */
/* Views: Manage template and view events. */

// Book/Views.js
BookAttributesView = Marionette.ItemView.extend({
    el: "#BookAttributesBox",
    template: "#BookAttributesTemplate",
    bindings:
    {
        "#Title": "Title",
        "#AuthorName": "AuthorName",
        "#LanguageCode": {
            observe: "LanguageCode",
            selectOptions: {
                collection: LanguageChannel.data.languages,
                labelPath: "Name",
                valuePath: "Code"
            },
            update: function($el, val, model, options) {
                window.console && console.log("View.bindings.#LanguagageCode:update");
                LanguageChannel.data.languages.each(function(language){
                    // Find parent.
                    var parent = $el.find("#LanguageReadable");
                    if (language.get("isEditable")){
                        parent = $el.find("#LanguageEditable");
                    }

                    // Select correct value.
                    var selected = "";
                    if (language.get("Code") == val){
                        selected = ' selected="selected"';
                    }

                    // Add option to optgroup.
                    parent.append("<option" + selected + ">" + language.get("Name") + "</option>");
                });
            }
        }
    },
    onRender: function () {
        window.console && console.log("View.onRender");
        this.stickit();
    }
});



/* ----------------------------------------------------------------------------- */
/* Controllers: Manage page behaviour. */

// Books/Controller.js: 
BookController = Marionette.Controller.extend({
    initialize: function(){
        window.console && console.log("Controller.ctor");
        var self = this;
        self.bookId = "978-1-4493-9268-0" 
        // Callbacks from data channels.
        self.listenTo(LanguageChannel.data.languages, "sync", self.onSyncLanguages);                           
        self.listenTo(BookChannel.data.book, "sync", self.onSyncBook);

        // Retrieve data.
        LanguageChannel.channel.commands.execute("getLanguages");
        BookChannel.channel.commands.execute("getBook", self.bookId);
    },
    /* Book functions */
    onSyncBook: function(){
        window.console && console.log("Controller.onSyncBook");
        this.showBookAttributes(); // TODO, use : LanguageChannel.data.languages.fetch();
    },
    showBookAttributes: function(){
        window.console && console.log("Controller.showBookAttributes");
        new BookAttributesView({ model: BookChannel.data.book }).render();
    },
    /* Language functions */
    onSyncLanguages: function(){
        window.console && console.log("Controller.onSyncLanguages")
        this.showBookAttributes();
    }
});



/* ----------------------------------------------------------------------------- */
/* Aplication.js: Starts the backbone application (main entry point). */

// Book/Application.js
Application = Marionette.Application.extend({
    onStart: function(){
        window.console && console.log("Application.start()");
        new BookController();
    }    
});

fiddle link to show how to do- of course, in your project, you need to "requirify your several modules".

fiddle link is based on C0b0ll -actually, a colleague- did on stickit usage-yes another jsFiddle link

doing so, the console will log this:


  • Application.start()
  • Controller.ctor
  • LanguageChannel.channel.command.getLanguages()
  • Controller.onSyncLanguages
  • Controller.showBookAttributes
  • View.onRender
  • View.bindings.#LanguagageCode:update
  • BookChannel.channel.commands.getBook(978-1-4493-9268-ø)
  • View.bindings.#LanguagageCode:update
  • Controller.onSyncBook
  • Controller.showBookAttributes
  • View.onRender
  • View.bindings.#LanguagageCode:update
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top