我想转换一个使用XMLHttpRequest()(或ActiveXObject,如果需要)的工作javascript函数来执行从服务器到异步数据的同步数据提取,如果它可以毫不费力地完成。今天这个函数“缓存”所收到的数据,因此只需要获取一次。当我执行“简单”的事情,只是选择XMLHttpRequest()的异步选项来使用提供的回调功能异步执行提取时,我的函数的调用者不会获取他们的数据,因为它通常不是从服务器返回,所以这一刻就失去了。数据返回后,当然没有问题,但由于许多调用必须来自onload,因此不容易重复。 (有没有办法在加载完成后“触发”inload列表中的所有函数?这可能是绕过该问题的另一种方法。)
相反,当它同步完成时,系统工作正常。在数据返回之前,某些事情会略有延迟,但通常情况下,这是一个问题(目前为止)还不够。但是,不推荐使用此用法。例如,Firefox的开发人员控制台报告:
主线程上的同步XMLHttpRequest因不推荐使用 它对最终用户的体验产生不利影响。获得更多帮助 http://xhr.spec.whatwg.org/
因为我真的不知道任何其他机制(这就是这个问题的全部内容),所以我想我必须使我的函数调用XMLHttpRequest()以某种方式跟踪它从其他函数接收的调用并承担在收到数据后执行他们需要做的任何事情的责任。调用函数可能可以分为两部分,一部分请求数据,另一部分可以在数据显示时完成所需的任务。使用XMLHttpRequest()的函数可以实现这一点,例如,通过向其函数签名添加许多参数,例如稍后调用的函数等等。 ......我认为它可以完成,但这是一个非常糟糕的混乱。必须有一个更好的方法,我只想提出一个。
要清楚,代码现在就像同步一样。我正在寻找一种更简单的方法来使它异步。这似乎并不容易!
以下是同步执行代码的代码片段:
var xmlhttp;
var dn = window.location.hostname;
var srcURL = "http://"+dn+"/unpublished/latest/this.txt";
if (window.XMLHttpRequest)
{
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else {// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("POST", srcURL, false);
xmlhttp.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
xmlhttp.send("fname=Who&lname=Cares");
if (xmlhttp.readyState == 4 && xmlhttp.status==200)
{
var siteData = xmlhttp.responseText;
. . .
异步版本 - 在获取数据时工作正常,但对某些调用者来说太迟了 - 非常相似。以下是它的片段:
if (window.XMLHttpRequest)
{
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else {// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
//the callback function to be called when AJAX request comes back
xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readyState == 4 && xmlhttp.status==200)
{
var siteData = xmlhttp.responseText;
... etc ...
以下是呼叫者的样子示例。请注意,getSiteData()
是包含上述代码段的函数。即:
<script type = "text/javascript">
function setLinkToContact(objId)
{
document.getElementById(objId).setAttribute('href',
getSiteData('contact'));
}
</script>
一个"getSiteData()"
函数有很多这样的调用者。
答案 0 :(得分:0)
我多次尝试理解你的问题。多个页面需要来自异步函数调用的数据。每个页面都有唯一的数据要求,这些要求取决于异步回调。
如果这是正确的,这是您可以尝试的方法。
在每个页面的顶部,在异步请求开始之前,在每个页面上声明一个空的全局函数。
window.myAsyncCallback = function(){}
让每个页面声明一个处理异步回调的函数。
page1
var handleCallback1 = function(data){
// unique handler 1
}
page2
var handleCallback2 = function(data){
// unique handler 2
}
将handlerCallback1和handlerCallback1分配给myAsyncCallback。
window.myAsyncCallback = handleCallback1;
window.myAsyncCallback = handleCallback2;
然后在 onreadystatechange 功能中。使用数据执行 window.myAsyncCallback(data)。当数据可用时,将触发每个具体实现。那么你现在可以使用它,它现在可以使用它。
**********更新更新********
您是否能够更新对“getSiteData('contact')的调用?”如果是这样,可以考虑调用getSiteData.call()函数并将其引用传递给需要网络数据的dom元素。然后在getSiteData内部,设置元素的数据集值。将元素存储在数组中,以便在网络请求完成后检索它。然后循环遍历元素列表,查找它的值,并根据需要进行更新,因为您将引用dom元素。
如果您无法修改调用者函数,请尝试使用函数原型进行操作。重构可能是很多工作,但似乎是避免引入竞争条件的最佳选择。如果你重构asynch,函数回调应该适合你,而不必进入Promises和EventListeners;这两个仍然是很好的选择,但回调是精益的,以满足您的需求。
我很想知道你是如何解决它的。如果可能,请让我发布。
<title></title>
<script>
var elements = [];
var getSiteData = function(elem, value){
// set element data
elem.dataset = value;
// store
elements.push(elem);
// mimic async request
setTimeout(function(){
var xmlHttpData = {
"contact":"http://www.yahoo.com",
"contacttwo":"http://www.google.com"
}
linklist.forEach(function(element, index, arr){
// match dataset value in element to xmlHttpData.
//element.dataset.value
})
},3000);
}
function setLinkToContact(objId){
document.getElementById(objId).setAttribute('href',
getSiteData.call(document.getElementById(objId),'contact'));
}
</script>
<body>
<a id="link" href="">my link</a>
<div id="linktwo">my link</a>
<script>
setLinkToContact('link');
setLinkToContact('linktwo');
</script>
</body>