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

异步、回调和OOP JavaScript:我如何组织它?,javascript,oop,asynchronous,xmlhttprequest,Javascript,Oop,Asynchronous,Xmlhttprequest,我正在构建一个插件,用于获取JSON中一组图像的信息,然后将它们显示在某个对话框中供选择。不幸的是,我的第一个直觉很清楚地导致了一种竞赛状态: var ImageDialog = function () {}; ImageDialog.prototype.items = []; ImageDialog.prototype.fetch_images() { var parse_images = function(data) { // Magically parse the

我正在构建一个插件,用于获取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\u images
方法会调用一堆关于显示图像的东西

那么:我应该在这里做什么

我很确定延迟会有所帮助,但唉:我需要在没有任何外部库的情况下编写此文档(

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

这个怎么样

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

通常,您可以使用的基本思想是,当常规程序使用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()
})

通过使用回调,您可以很好地模拟传统程序的功能(事实上,这是一种形式和另一种形式之间相当机械的转换)。您现在遇到的唯一问题是错误处理变得棘手,像循环这样的语言功能在异步回调中不起作用,而calback往往嵌套在回调地狱中。如果回调开始变得太复杂,我会研究使用一种Javascript方言,编译成延续传递样式的Javascr它(其中一些在运行时不需要额外的库就可以工作)。

下面是一个关于如何做的想法

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

通过这种方式,我不会传递一些实现细节来获取图像,也不会获取缓存来引导。我是否仍在试图逃避CPS,或者这是否合理?

我认为承诺对您来说是一个好的解决方案。请看一下这个库,例如:。维基百科:。她是一个jQuery延迟的示例,在我的回答末尾:。Felix,我同意承诺和尊重对这一点很好。不幸的是,正如我在问题中所说的,我不能为这个项目使用任何库。:(谢谢链接——我会查出来的!哦,对不起,我没有看到那部分:-/(我现在觉得很傻)。但是,自己实现基本的承诺/延迟功能应该不会太难。请查看该库的源代码。
var foo=function
也有味道;)还有一种气味:that.items=数据将隐藏原型的items属性。这实际上很好,否则所有实例都将共享相同的数据。结论:摆脱ImageDialog.prototype.items=[];说得很好。我知道我可以像GGG建议的那样使用这样的CPS。不幸的是,在一个非常OOP的环境中,我对这个问题的理解是错误的。
display\u images
到底与
fetch\u images
有什么关系,所以它应该是一个参数?它的名称是否更好在这一点上使用(我想我可能是太努力了,让这看起来像是非异步编程。)好吧,好吧。我想我需要停止担心,爱上CPS。谢谢你的帮助!@Bacon:讨厌回调没关系。但你需要习惯它们:)