javascript - 连接来自 JavaScript XMLHttpRequest 的多个响应

标签 javascript scope xmlhttprequest string-concatenation

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

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

当我完成请求后,我希望此变量具有以下字符串值:

<script src='foo/bar/script.js'></script><div>content</div>

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

<div class="target-element">
    <script src='foo/bar/script.js'></script><div>content</div>
</div>

我在我的代码中不明白的是,为什么我在 storeHttpResult 中的 console.log 反射(reflect)了我期望的 combinedHttpResult 变量,但在getContentcombinedHttpResult未修改。

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);

最佳答案

这是竞争条件的问题。要清楚地了解问题的性质,您必须了解 javascript 中的“Event Loop”是如何工作的。

长话短说(希望您能观看该视频)是您的代码没有按照编写的顺序执行。

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

  • storeHttpResult 被调用
  • 创建了一个 XMLHttpRequest 实例
  • 已注册 XMLHttpRequest 事件“onreadystatechange”的处理程序
  • 调用 getText(htmlLoc, storeHttpResult)

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

在这种情况下,这种异步的解决方案。操作被创建。最简单的是 Promises .这取决于您必须支持哪种浏览器,但如果它恰好是现代浏览器,我强烈建议您使用 Promises。

使用 promises 的解决方案可能看起来像这样:

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);

请注意,此代码可以改进一些内容,但了解如何处理 Promises 是一个很好的开始。

存在其他解决方案,例如 GeneratorsObservables如果您想更深入地研究该主题。

关于javascript - 连接来自 JavaScript XMLHttpRequest 的多个响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51575055/

相关文章:

javascript - 在这种情况下如何获取标签文本?

javascript - Applescript,单击带有 do JavaScript 的复选框

php - 将 php 值传递给 javascript

Javascript 作用域和递归

javascript - HTTP解析器: scraping single page application: many GETs,如何找出页面何时结束

javascript - 获取与评估代码一起使用的源映射

javascript - 来自其他文件的函数未定义

javascript - Chrome 忽略扩展中来自 XMLHttpRequest 的 Set-Cookie 响应 header

javascript - 为什么我不能从外部服务器加载外部脚本而 Modernizr.load 可以?

javascript - 过滤$范围错误: Unknown provider: $scopeProvider <- $scope <- transformSensorStatusFilter