【问题标题】:Callback response/status for Backbone.Wreqr request-response handler when it is doneBackbone.Wreqr 请求-响应处理程序完成时的回调响应/状态
【发布时间】:2014-04-03 15:57:00
【问题描述】:

使用 jquery deferred.resolve 方法的通常方法是在您有一个回调函数时调用它,该函数会为您提供它们已完全加载的响应,因为在这种情况下,xhr 在加载时添加一个事件侦听器并提供xhr 对 deferred.resolve 的响应。

以下代码是从其中一个示例中复制而来的。 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();
}

我当前使用 Marionette 请求-响应处理程序检索数据的代码。无论如何我可以从以下请求中获得回调响应

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();
};

请求处理程序基本上将返回一个 Backbone 集合,该集合将通过将对象集合传递给新的 Backbone 集合来生成。

【问题讨论】:

    标签: javascript marionette jquery-deferred backbone-events


    【解决方案1】:

    如果(看起来)require() 是异步的,而App.request() 是同步的,那么您可以编写如下代码:

    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
    });
    

    或者,取决于您想在getData() 中做多少/很少,如下所示:

    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
    });
    

    但是,如果App.request()也是异步的,那么它就不能返回数据——它必须返回一个数据的promise,代码应该是这样的:

    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
    });
    

    或:

    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
        });
    });
    

    如果App.request() 是异步的,既不返回承诺也不接受回调,则需要与编写它的人交谈。 App.request() 需要重写,否则您需要找到另一个实用程序来完成这项工作。

    【讨论】:

    • 感谢@Roamer-1888 的详细解释。基本上我使用的是方法 1,这是我的初始代码,但我使用它来调用另一个请求,该请求应该在当前调用之前首先完成。安排我的代码后,它的工作原理!确实需要检查 App.request() 也是异步的。还有一件事,我添加了 $.when 如下 $.when(getData()).done(function(data){});
    • Cheng, $.when(getData()) 在这种情况下不是必需的,因为getData() 将可靠地返回一个不需要强制的 jQuery 承诺。但是,如果您愿意,请务必使用$.when(getData()) - 除了比简单的getData() 稍慢之外,它不会造成任何伤害。
    【解决方案2】:

    默认情况下,从服务器获取数据是异步调用,那么为什么不使用命令而不是请求/响应并监听模型事件呢?我认为这会更容易。 在这个话题上,我会创建一个频道来提供,

    1. 获取数据的命令
    2. 通道应用的模型或集合实例。

    然后控制器只需订阅通道以获取数据并监听集合实例事件(同步错误更改,无论您想要模型/集合上的任何基本主干事件)

    /* 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 展示如何做——当然,在你的项目中,你需要“要求你的几个模块”。

    fiddle 链接基于 C0b0ll - 实际上,一位同事 - 在 stickit usage-yes another jsFiddle link 上做的

    这样做,控制台将记录以下内容:


    • 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

    【讨论】:

      猜你喜欢
      • 2021-10-31
      • 2020-04-24
      • 2021-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-23
      • 1970-01-01
      • 2017-10-31
      相关资源
      最近更新 更多