我正在尝试使用一些面向对象的 Javascript来保持我的代码干净,而不是像往常一样有一个巨大的凌乱脚本.使用Ajax使其变得复杂,具有异步特性,难以分离代码. 我遇到的一个具体问题是使用
我遇到的一个具体问题是使用Ajax设置对象属性.
我有以下代码:
var Class = function(){ this.attr1; } Class.prototype.setAttr1 = function(){ var self = this; $.ajax({ url:'http://api.something.com?get=somedata', success: function(data){ self.attr1 = data.name; } }); }
这应该有效,但是如果我从其他地方访问该属性,我无法确定该属性是否已设置,对吗?有没有办法解决这个问题.就像我需要在某处使用attr1一样,我可以等待ajax返回吗?或者,如果我完全关闭,人们如何在使用Ajax时封装代码?
This should work, but I can’t really be certain that the property is set if I access it from somewhere else, correct?
正确
Is there a way to deal with that. Like if I need to use attr1 somewhere, can I wait for the ajax to return or something?
是的:你想在哪里使用attr,让访问者接受一个回调(直接或间接地通过返回一个promise),并让它在属性可用时调用回调(或解析promise).
看起来您希望将启动ajax调用的代码与稍后使用该属性值的代码分开.如果是这样,基于承诺的机制在这种情况下可能会更有用.当你使用jQuery时,这是一个使用jQuery的Deferred和Promise的jQuery示例:
var Class = function(){ this.attr1LoadDeferred = $.Deferred(); } Class.prototype.setAttr1 = function(){ var self = this; $.ajax({ url:'http://api.something.com?get=somedata', success: function(data){ self.attr1 = data.name; self.attr1LoadDeferred.resolveWith(self); } }); } Class.prototype.accessAttr1 = function() { return this.attr1LoadDeferred.promise(); };
用法:
// Create an instance var c = new Class(); // At some point, initiate loading the value c.setAttr1(); // At some point, look to use the value c.accessAttr1().then(function(inst) { console.log(inst.attr1); }); // Somewhere else, look to use the value c.accessAttr1().then(function(inst) { doSomethingElseWith(inst.attr1); });
不幸的是,jQuery的Deferred / Promise实现有一个问题,大多数承诺库都没有:你传递的回调有时会被异步调用,有时会同步调用. (具体来说:如果promise已经解决,则回调是同步的.)要么在使用它时要记住这一点,要么使用不同的promise实现.