需要来自异步API调用的数据的构造函数?

时间:2012-06-06 06:35:24

标签: javascript jquery asynchronous constructor callback

我想知道我应该采取什么样的方法来使这个代码按照预期的方式运行。 API调用是异步的 - 因此构造函数在加载数据之前返回。

addSongById: function (songId) {
    var song = new Song(songId);
    console.log(song);
    this.addSong(song);

    if (this.songCount() == 1)
        this.play();

    UserInterface.refresh();
    SongGrid.reload();
},

function Song(songId) {
    $.getJSON('http://gdata.youtube.com/feeds/api/videos/' + songId + '?v=2&alt=json-in-script&callback=?', function (data) {
        this.id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); });
        this.songId = songId;
        this.url = "http://youtu.be/" + songId;
        this.name = data.entry.title.$t;
    });
}

是否可以强制构造函数不能过早返回?理想情况下,我不必将任意数量的参数传递给Song构造函数,并将仅与Song相关的信息带到其范围之外。

4 个答案:

答案 0 :(得分:7)

与大多数异步操作一样,在这种情况下我会使用Deferred; JS中的构造函数没有义务返回自己的实例:

function Song(songId) {
    var song = this;
    var def = new $.Deferred();
    $.getJSON('http://gdata.youtube.com/feeds/api/videos/' + songId + '?v=2&alt=json-in-script&callback=?', function (data) {
        song.id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); });
        song.songId = songId;
        song.url = "http://youtu.be/" + songId;
        song.name = data.entry.title.$t;
        def.resolve(song);
    });
    return def.promise();
}

var promise = new Song(songId);
promise.done(function(instance) {
    // you've got a Song instance
});

答案 1 :(得分:3)

您可能希望$.ajax而不是$.get使用选项async: false。然而,这将锁定每个其他JavaScript的执行。如果服务器因任何原因无法响应,这可能会成为一个问题。

因此这是一种不好的做法。使用回调,例如

function Song(songId, callback) {
    var self = this;
    $.getJSON('http://gdata.youtube.com/feeds/api/videos/' + songId + '?v=2&alt=json-in-script&callback=?', function (data) {
        self.id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); });
        self.songId = songId;
        self.url = "http://youtu.be/" + songId;
        self.name = data.entry.title.$t;
        callback();
    });
}

var song = new Song(songId, function() {
    // The other code goes here.
});

答案 2 :(得分:3)

  

......这是一种不好的做法。构造函数应该返回一个实例   它的班级,没有别的。它会弄乱新的操作员和   否则继承。

     

此外,构造函数应该只创建和初始化一个新的   实例。它应该设置数据结构和所有特定于实例的   属性,但不执行任何任务。它应该是一个纯粹的功能   如果可能的话,没有副作用,具有所有的好处。

参考:Is it bad practice to have a constructor function return a Promise?

答案 3 :(得分:0)

同步调用可能会导致浏览器停止响应,某些浏览器可能会强行终止您的脚本。

Jquery在向URI发送请求时有一个选项

  

asyncBoolean默认值:true

     

默认情况下,所有请求都是异步发送的(即设置为   默认为true)。如果需要同步请求,请将此选项设置为   假。跨域请求和dataType:“jsonp”请求没有   支持同步操作。请注意,同步请求可能   暂时锁定浏览器,在请求时禁用任何操作   活跃。从jQuery 1.8开始,不推荐使用async:false。

http://api.jquery.com/jQuery.ajax/

希望这会有所帮助

问候。