异步,回调和OOP JavaScript:我该如何组织它?

时间:2013-03-20 01:25:16

标签: javascript oop asynchronous xmlhttprequest

我正在构建一个插件,用于获取JSON中的一堆图像的信息,然后在一些对话框中显示它们以供选择。不幸的是,我的第一个直觉很明显会导致竞争条件:

var ImageDialog = function () {};
ImageDialog.prototype.items = [];

ImageDialog.prototype.fetch_images() {
    var parse_images = function(data) {
        // Magically parse these suckers.
        data = awesome_function(data);
        this.items = data;
    };

    magicalxhrclass.xhr.send({"url": 'someurl', "success": parse_images, "success_scope": this});
}

ImageDialog.prototype.render = function () {
    this.fetch_images();
    // XHR may or may not have finished yet...
    this.display_images();
    this.do_other_stuff();
};

var monkey = new ImageDialog();
monkey.render();

我认为可以通过更改parse_images回调以包含其余的渲染步骤来解决这个问题。但是,这看起来不太合适。为什么fetch_images方法会调用一堆关于显示图像的东西?

那么:我该怎么办?

我非常肯定deferreds会有所帮助,但是唉:我需要在没有任何外部库的情况下编写它。 :(

对其他代码气味的评论也会很好!

3 个答案:

答案 0 :(得分:2)

这个怎么样?

var ImageDialog = function () {
    this.items = []; // just in case you need it before the images are fetched
};

ImageDialog.prototype.fetch_images(callback) {
    var that = this;
    function parse_images (data) {
        // Magically parse these suckers.
        data = awesome_function(data);
        that.items = data;
        callback.apply(that);
    };

    magicalxhrclass.xhr.send({"url": 'someurl', "success": parse_images, "success_scope": this});
}

ImageDialog.prototype.render = function () {
    this.fetch_images(function(){
        this.display_images();
        this.do_other_stuff();
    });
};

var monkey = new ImageDialog();
monkey.render();

答案 1 :(得分:2)

一般来说,你可以使用的基本思想是当常规程序使用return语句时(意思是“我的函数现在完成你的工作!”)异步延续传递程序将使用ballcabk函数得到明确称为

function fetch_images(callback){
   magicalXHR({
       success: function(data){
           parse_images(data);
           callback(whatever);
       }
   }
}

或者,如果parse_images本身是异步函数:

parse_images(data, callback)

现在当你调用fetch_images后代码进入回调而不是假设fetch_images将在返回时完成

fetch_images(function(
   display_images()
})

通过使用回调,您可以很好地模拟传统程序可以做什么(实际上它是另一种形式之间的相当机械的转换)。你现在遇到的唯一问题是错误处理变得棘手,像循环这样的语言功能不能很好地处理异步回调,并且回调倾向于嵌入到回调地狱中。如果回调开始变得过于复杂,我会调查使用其中一种Javascript方言,这些方言编译为延续传递式Javascrit(其中一些工作在运行时不需要额外的库)。

答案 2 :(得分:0)

这是一个关于该怎么做的想法。

ImageDialog.prototype.fetch_images() {
    var parse_images = function(data) {
        // Magically parse these suckers.
        data = awesome_function(data);
        this.items = data;
        fetch_images.caller() // Unfortunately, this is nonstandard/not in the spec. :(
    };

    magicalxhrclass.xhr.send({"url": 'someurl', "success": parse_images, "success_scope": this});
}

ImageDialog.prototype.render = function () {
    if (this.items === []) {
        this.fetch_images()
        return;
    } else {
        this.display_images();
        this.do_other_stuff();
    };
};

这样我就不会将一些实现细节传递给fetch_images,而是进行缓存,以便启动。我是否仍在努力逃避CPS,或者这是否明智?