首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >连接来自JavaScript XMLHttpRequest的多个响应

连接来自JavaScript XMLHttpRequest的多个响应
EN

Stack Overflow用户
提问于 2018-07-29 04:33:55
回答 1查看 960关注 0票数 2

我有来自两个不同URL的HTML内容,我需要将它们附加到一个HTML元素。

使用JavaScript ES5,我尝试创建一个字符串变量,并简单地连接两个HTTP请求的结果。

当我完成我的请求时,我希望这个变量具有以下字符串值:

代码语言:javascript
复制
<script src='foo/bar/script.js'></script><div>content</div>

然后,我希望获取该变量并将其(使用jQuery)附加到页面中的一个HTML元素。最终目标是用两个HTTP请求的结果填充div,如下所示:

代码语言:javascript
复制
<div class="target-element">
    <script src='foo/bar/script.js'></script><div>content</div>
</div>

我在代码中不理解的是,为什么我在storeHttpResult中的console.log会像我期望的那样反映combinedHttpResult变量,而在getContent中,combinedHttpResult却没有被修改。

代码语言:javascript
复制
var libsLocation = 'http://some/location/libs.html'; //contents: <script src='foo/bar/script.js'>
var htmlLocation = 'http://some/location/snippet.html'; //contents: <div>content</div>
var combinedHttpResult = '';

// taken from David Flanagan JavaScript book, p499:
function getText(url, callback) { 
    var request = new XMLHttpRequest();         
    request.open('GET', url);                   
    request.onreadystatechange = function() {   
        if (request.readyState === 4 && request.status === 200) {
            var type = request.getResponseHeader("Content-Type");
            if (type.match(/^text/))            // make sure the response is text
                callback(request.responseText); // pass it to the callback
        }
    };
    request.send(null);
}
function storeHttpResult(e) {   
    console.log('before: ' + combinedHttpResult);
    combinedHttpResult += e;   
    console.log('after: ' + combinedHttpResult);
}
function getContent(libLoc, htmlLoc) {
    console.log('**** ' + combinedHttpResult);
    if ($('.target-element').length > 0 ) {
        $('.target-element').each(function() {
            getText(libLoc, storeHttpResult);
            getText(htmlLoc, storeHttpResult);

            $(this).append(combinedHttpResult); // empty string - why?
        });
    }
    console.log('~~~~ ' + combinedHttpResult);
}
getContent(libsLocation, htmlLocation);
EN

回答 1

Stack Overflow用户

发布于 2018-07-29 05:23:34

这是一个竞态条件的问题。为了清楚地理解问题的本质,你必须理解javascript中的"Event Loop“是如何工作的。

长话短说(希望你会看这个视频)是你的代码没有按照编写的顺序执行。

您所期望的是,当您调用getText()时,它将调用所有底层函数,但是这里的执行流程有点不同步。下面是调用getText(libLoc,storeHttpResult)时发生的情况;

  • storeHttpResult is registered
  • getText(htmlLoc,is
  • XMLHttpRequest is
  • XMLHttpRequest is onreadystatechange is onreadystatechange is registered
  • getText(htmlLoc,storeHttpResult is

事件的一个实例被创建并被调用

请注意,最后一步是调用getContent上的下一个表达式。storeHttpResult将在请求完成时执行,您无法预测它将在何时发生。

在这种情况下,这种异步的解决方案。操作已创建。最简单的例子是Promises。这取决于你必须支持什么浏览器,但如果它恰好是一个现代的浏览器,我强烈建议你使用Promises。

使用promises,解决方案可能如下所示:

代码语言:javascript
复制
function getText(url) { 
    return new Promise(function(resolve){
      var request = new XMLHttpRequest();         
      request.open('GET', url);                   
      request.onreadystatechange = function() {   
        if (request.readyState === 4 && request.status === 200) {
            var type = request.getResponseHeader("Content-Type");
            if (type.match(/^text/))            // make sure the response is text
                resolve(request.responseText); // pass it to the callback
        }
      };
      request.send(null);
    });
}

function getContent(libLoc, htmlLoc) {
    console.log('**** ' + combinedHttpResult);
    if ($('.target-element').length > 0 ) {
        $('.target-element').each(function() {
            var self = this;
            Promise.all([getText(libLoc), getText(htmlLoc)]).then(function(response){
              $(self).append(response[0]);
              $(self).append(response[1]);
            });
        });
    }
    console.log('~~~~ ' + combinedHttpResult);
}
getContent(libsLocation, htmlLocation);

请注意,这段代码可以改进一些东西,但理解如何处理Promise是一个很好的开始。

如果您想更深入地挖掘这个主题,还存在其他解决方案,如GeneratorsObservables

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51575055

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档