异步、回调和OOP JavaScript:我如何组织它?
我正在构建一个插件,用于获取JSON中一组图像的信息,然后将它们显示在某个对话框中供选择。不幸的是,我的第一个直觉很清楚地导致了一种竞赛状态:异步、回调和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
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:讨厌回调没关系。但你需要习惯它们:)