【问题标题】:await Backbone.Collection.fetch() does not waitawait Backbone.Collection.fetch() 不等待
【发布时间】:2017-10-15 11:21:44
【问题描述】:

jsfiddle

testcase.xhtml

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8" />
        <title />
        <script src="jquery-3.2.1.js"></script>
        <script src="underscore-1.8.3.js"></script>
        <script src="backbone-1.3.3.js"></script>
        <script src="testcase.js"></script>
    </head>
    <body />
</html>

testcase.js

class My_Collection extends Backbone.Collection {}
class My_View extends Backbone.View {
    async initialize() {
        let collection = new My_Collection;
        collection.url = 'http://backgridjs.com/examples/territories.json';
        console.log(collection);
        await collection.fetch();
        console.log(collection);
        $.extend(this, {collection});
        return this;
    }
    render() {
        console.log('render→→→', Date.now(), this.collection);
        this.collection.map(foo => foo);
    }
}

const view = new My_View;
view.render();

结果是

testcase.js:13:9 Object { length: 1, models: Array[1], _byId: Object, url: "http://backgridjs.com/examples/terr…" }
testcase.js:21:9 render→→→ 1494928366647 undefined
testcase.js:22:9 TypeError: this.collection is undefined
testcase.js:16:9 Object { length: 242, models: Array[242], _byId: Object, url: "http://backgridjs.com/examples/terr…" }

尽管有await,但请注意乱序执行。 Collection.fetch() is documented to return 一个实现 Promise 的 jqXHR

我希望执行在 fetch() 上等待,将集合数据附加到视图,并呈现为不会在未定义的值上崩溃。我看不出哪里出错了。正确的代码是什么样的才能使其按预期工作?

【问题讨论】:

  • 无论调用什么初始化,我都认为它会返回一个 Promise 并等待它解决(使用 await 或 .then),然后再继续......对吗?
  • @JaromandaX 不,它没有......
  • $.extend(this, {collection}); 为什么要使用 jQuery 的 extend 进行简单的赋值?
  • Emile B:因为这是真实代码的simplification,在这个地方有多重赋值。忽略这一点,它与问题无关。

标签: javascript jquery backbone.js async-await es6-promise


【解决方案1】:

注意以下几点:

async initialize() {

您使 initialize 异步,现在无法保证当您调用 view.render(); initialize 时完成执行。您必须访问async initialize() 返回的承诺并在解决后调用render,我不确定是否可以使用主干,因为即使是 1.3.3 源代码(最新版本 afaik)也看起来像这样:

var View = Backbone.View = function(options) {
  this.cid = _.uniqueId('view');
  _.extend(this, _.pick(options, viewOptions));
  this._ensureElement();
  this.initialize.apply(this, arguments);
  // ^----- Does not return the promise,
  // and shouldn't because this is supposed to be a constructor
};

你会更喜欢老式的

collection.fetch().then(this.render.bind(this));

为什么不使用已经可用的承诺?

【讨论】:

  • 您应该将context 选项与fetch 一起使用,以便使用正确的上下文调用render
  • then(this.render) 传递 render 作为没有上下文的引用。当集合的承诺将解决时,render 内部的this 不会指向视图实例。 fetch({context: this, success: this.render }) 会起作用。
  • @EmileBergeron 是的,这是正确的,有很多方法可以解决这个问题,contextbind,或箭头函数,因为他使用的是 es6 我很难选择一个:D跨度>
  • @daxim 在责任对象而不是initialize 中调用view.collection.fetch({ /*...*/ })。或者只是在负责对象的集合上附加一个侦听器。
  • @daxim Emile 上面的建议,你甚至可以把它放在像{loadDataAndRender: function(){ this.collection.fetch({ /*...*/ }) }} 这样的方法中,然后从像view.loadDataAndRender(); 这样的其他对象调用它而不是初始化......我的问题是为什么使用@ 987654342@ 关键字而不是可用的承诺 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-03
  • 2021-12-11
  • 2016-03-08
  • 1970-01-01
  • 2020-07-23
  • 2019-10-16
相关资源
最近更新 更多