我有一个有趣的情况,我通常很聪明的头脑无法提出解决方案:)这是情况......
我有一个具有get()方法的类......调用此方法来获取存储的用户首选项...它所做的是调用某个底层提供程序来实际获取数据...现在写的,它正在调用一个会话cookie的提供者...所以,get()调用providerGet()让我们说,providerGet()返回一个值,get()将它传递给调用者。调用者希望在它继续工作之前做出响应。
这是棘手的部分......我现在正在尝试实现一个异步的提供程序(在这种情况下使用本地存储)...所以,providerGet()会立即返回,已经调用了本地调用存储将在一段时间后调用传递给它的回调函数...但是,由于providerGet()已经返回,所以get()现在通过扩展到原始调用,它显然没有返回实际检索的数据。
所以,问题是,是否有一种方法可以基本上“阻止”从providerGet()返回,直到异步调用返回?请注意,出于我的目的,我并不关心这可能带来的性能影响,我只想弄清楚如何使其工作。
我认为没有办法,当然我知道我无法想出来......所以我想把它扔掉,看看别人能想出什么:)
编辑:我现在只是在学习问题的核心,即web sql API是非同步的这一事实,可能有一个解决方案......原来还有一个同步版本的API,我没做过我意识到......我现在正在阅读文档以了解如何使用它,但这可以很好地解决问题,因为providerGet()完全异步编写的唯一原因是允许该提供程序...代码get()是我自己的抽象层的一部分是在各种存储提供者(cookies,web sql,localStorage等)之上,所以最低的共同点必须赢,这意味着如果一个是异步的,他们都必须是异步的..唯一的一个是web sql ...所以如果有一种方法可以同步地做到这一点我的观点变得没有实际意义(尽管我认为仍然是一个有趣的问题)
edit2:好吧,似乎没有任何帮助......似乎API的同步版本没有在任何浏览器中实现,即使它被指定它只能在工作线程中使用,所以这个看起来似乎没有任何帮助。虽然,读一些其他的东西,听起来有一种方法来使用递归来拉动这个技巧...我现在正在抛出一些测试代码,如果/当我让它工作时我会发布它,看起来像一个非常有趣的通常可以解决任何这种情况。
edit3:根据我下面的评论,我真的没办法完全按照自己的意愿行事。我要解决我当前问题的解决方案是不允许使用Web SQL进行数据存储。它不是理想的解决方案,但是由于该规范不断变化而且没有广泛实施,它不是世界末日......希望当它得到适当的支持时,同步版本将可用,我可以插入新的提供商,很高兴去。一般来说,似乎没有任何方式可以拉动这个奇迹...确认我的预期是这样的,但希望我错了一次:))
答案 0 :(得分:13)
生成一个webworker线程来为您执行异步操作。 传递它需要执行任务加上唯一ID的信息。 诀窍是让它在结束时将结果发送到网络服务器。
同时......产生webworker的函数向同一个webserver发送ajax请求 使用xmlhttprequest对象的同步标志(是的,它有一个同步选项)。因为它会阻塞直到http请求完成,你可以让你的webserver脚本轮询数据库以获取更新或其他任何内容,直到结果发送给它。
我知道,丑陋。但它会阻止cpu:D基本上
function get(...) {
spawnWebworker(...);
var xhr = sendSynchronousXHR(...);
return xhr.responseTEXT;
}
答案 1 :(得分:8)
不,在异步调用完成之前,您无法阻止。就这么简单。
听起来您可能已经知道这一点,但是如果您想使用异步ajax调用,那么您必须重新构建代码的使用方式。你不能只有一个.get()方法来进行异步ajax调用,阻塞直到它完成并返回结果。在这些情况下最常用的设计模式(例如,查看所有进行网络连接的Google的javascript API)是让调用者为您传递完成功能。对.get()
的调用将启动异步操作,然后立即返回。操作完成后,将调用完成功能。调用者必须相应地构造他们的代码。
在使用异步网络时,你根本无法编写直接的,顺序的程序性javascript代码,如:
var result = abc.get()
document.write(result);
最常见的设计模式是这样的:
abc.get(function(result) {
document.write(result);
});
如果您的问题是多个深层呼叫层,那么回调可以传递到不同的级别并在需要时调用。
答案 2 :(得分:3)
为什么不让原始调用者将自己的回调传递给get()
?此回调将包含依赖于响应的代码。
get()
方法会将回调转发给providerGet()
,然后在调用自己的回调时调用它。
获取的结果将传递给原始调用者的回调。
function get( arg1, arg2, fn ) {
// whatever code
// call providerGet, passing along the callback
providerGet( fn );
}
function providerGet( fn ) {
// do async activity
// in the callback to the async, invoke the callback and pass it the data
// ...
fn( received_data );
// ...
}
get( 'some_arg', 'another_arg', function( data ) {
alert( data );
});
答案 3 :(得分:1)
当您的异步方法启动时,我会打开某种模式对话框(用户无法关闭)告诉他们请求正在处理中。请求完成后,关闭回调中的模态。
执行此操作的一种可能方法是使用jqModal,,但这需要您将jQuery加载到项目中。我不确定这是不是你的选择。
答案 4 :(得分:1)
这很难看,但无论如何我认为这个问题有点暗示需要一个丑陋的解决方案......
或者,为了避免通过网络发送数据,您可以让iframe将结果编码为浏览器缓存的画布生成的图像(类似于Zombie cookie据称使用的方法)。然后你的阻止脚本会尝试不断地反复加载这个图像(每个请求都有一些小的网络生成的延迟),直到缓存的版本可用,你可以通过你设置的一些标志来识别它已经完成