从发起请求的相同javascript函数访问服务器响应

时间:2011-11-18 17:00:39

标签: javascript ajax asynchronous nonblocking

通过完全控制客户端和服务器端代码,我想完成以下任务:

  • 在javascript函数中启动服务器请求
  • 能够在指定时间后放弃请求(从用户体验角度来看)
  • 在退出原始函数之前访问有关响应的信息(例如,重定向URL或响应正文的一部分)(此部分是不可协商的;例如,设置窗口间隔,将不削减它)

这听起来很像我的多线程,当然javascript不行。也许没有解决方案,但在承认这一点之前我已经筋疲力尽了。在下面的非工作示例中,函数foo()将iframe的src设置为页面的url - redirect.aspx - 在短暂的延迟后重定向到另一个页面,其中包含一些UUID请求参数。 (注意:它也可以在响应主体的隐藏字段中返回UUID,或者通过其他策略;我可以控制它。)

无论 服务器页面如何返回结果,我的目标是在 foo()退出之前从服务器访问UUID。

更新:建议的单元测试 虽然这个问题出现关于范围 - 因此可以通过闭包解决(测试未决) - 它实际上是关于执行的连续性。成功的测试包括:

  • 创建foo()函数
  • 分配something.onClick = foo()
  • foo()以某种方式启动服务器调用并从响应中检索URL
  • foo()然后使用该网址调用window.open(url);
  • 所有主流浏览器都会打开一个窗口(关键案例:IE 7,8& 9)

我目前不知道可以通过此测试的策略。

非工作样本

<iframe id="aFrame" src="" height="0" width="0"></iframe>
<script type="text/javascript" language="javascript">
    function foo() {
        var f = document.getElementById("aFrame");
        var loc = "http://localhost:8080/redirect.aspx?after=1000";
        f.src = loc;
        var start = new Date().getTime();
        while (elapsedSince(start < 5000)) { // allow for server response
            // FAIL: this is never true until after foo() exits:
            if (f.src != loc) {
                alert(encodeURIComponent(f.src));
                return true;
            }
        }
        alert("Timeout");
        return false;
    }
    function elapsedSince(startTime) { // omitted safety checks for brevity:
        return new Date().getTime() - startTime;
    }
</script>

我不是Ajax函数的王牌,但根据我的理解,它们需要回调,这意味着任何返回信息都会在启动函数之外到达。失败。

根据js代码中的评论,上述策略不起作用。

其他策略可能包括使用document.createElement()创建iframe和.insertBefore()将其添加到DOM中,但我仍然不确定我是否能够同时启动foo()的同一次迭代中访问任何响应详细信息。

是否有人知道符合上述条件的任何策略?

1 个答案:

答案 0 :(得分:1)

以下是一些可以通过“测试”的代码。它从外部页面获取URL并打开一个包含该URL的新窗口。

在为readystatechange事件(回调)设置侦听器时,它是非阻塞的。

function foo() {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', '/pathname', true);
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
      window.open(xhr.responseText);
    }
  };
};

button.onclick = foo;