相邻的AJAX(改进)

时间:2016-03-13 18:23:03

标签: javascript ajax html5 api google-chrome

这个问题是在几天前发布的,但由于我是一个小块,它充满了意大利面条代码和那种东西(请原谅表格处理)除此之外,我添加了一些笔记和给出了一些上下文,但问题仍然在于第二次AJAX调用。

这是Chrome投掷的错误“仅支持协议方案的跨源请求:http,数据,Chrome,Chrome扩展,https,chrome-extension-resource。”

我隐藏了网址,因为它包含我不想分享的API密钥。

热烈欢迎任何批评

/*
This module will take a user's name, return an ID
then search more stats in the api with the ID.
*/


var search = document.getElementById('search');
search.addEventListener('click', function(){


	var demo = document.getElementById('demo');
	var player_name = document.getElementById('player_name').value;
	var player_id;

	// Interpolated API URLs
	var name_url = 'URL.pre'+player_name+'URL.end';
	var stats_url; //nested in the second ajax call to pass updated player_id


	// Get player ID
	var xhr = new XMLHttpRequest();
	var id_return_text;
	xhr.onload = function(){
		if(xhr.status === 200) {
			id_return_text = JSON.parse(xhr.responseText);
			player_id = id_return_text[player_name].id;
			demo.innerHTML = id_return_text[player_name].name +', your player ID is: '+player_id;
		}
	};
	xhr.open('GET', name_url, true);
	xhr.send();
	

	// Search stats with ID
	var xhr_2 = new XMLHttpRequest();
	var stats_return_text;
	xhr.done = function(){
		stats_url = "URL.pre"+player_id+"URL.end";
		if(xhr_2.status == 200) {
			stats_return_text = JSON.parse(xhr_2.responseText);
			demo.innerHTML += stats_return_text['playerStatsSummaries'].playerStatType;
		}
	};
	xhr_2.open("GET",stats_url, true);
	xhr_2.send();


});
<div id="container">
	<img id="duck" src="duck.png" alt="duck">
	<div class="form_wrapper">
		<h1 id="app_header">*QUACK* What's Your player ID?</h1>
		<form>
			<input
				type="text"
				id="player_name" 
				placeholder="Summoner Name">
			<input type="button" id="search" value="Search">
		</form>
	</div>
		<p id="demo"></p>
</div>

<script type="text/javascript" src="script.js"></script>

1 个答案:

答案 0 :(得分:1)

所以你的主要错误是,如果你需要发出CORS请求(或任何真正的AJAX请求),你需要从服务器(甚至是localhost)运行代码。

如果您的网页协议是&#34; file:///&#34;那么Google(以及大多数浏览器)都会对您不满。并且你试图从互联网上加载东西(反之亦然)。和&#34; file:///&#34;也无法请​​求其他文件。

未来参考:你也不能制作&#34; http&#34;来自&#34; https&#34;的请求页。

这样,第二个问题(CORS安全性隐藏的问题)就是你的AJAX请求正在并行运行。

为了让你的工作按照你认为应该的方式进行(在第一个返回后运行第二个),你需要:

  1. 移动底部的所有代码,与xhr_2
  2. 内的xhr.onload相关
  3. 移动xhr.done内部xhr.onload内的所有代码并替换所有重复信息(并直接使用对返回结果的引用)
  4. 这导致类似:

    var search = document.getElementById('search');
    search.addEventListener('click', function(){
    
    
      var demo = document.getElementById('demo');
      var player_name = document.getElementById('player_name').value;
      var player_id;
    
      // Interpolated API URLs
      var name_url = 'https://na.api.pvp.net/api/lol/na/v1.4/summoner/by-name/'+player_name+'?api_key=<THIS IS THE API KEY>';
      var stats_url; //nested in the second ajax call to pass updated player_id
    
    
      // Get player ID
      var xhr = new XMLHttpRequest();
      var id_return_text;
      xhr.onload = function(){
        if(xhr.status === 200) {
          id_return_text = JSON.parse(xhr.responseText);
          player_id = id_return_text[player_name].id;
          demo.innerHTML = id_return_text[player_name].name +', your player ID is: '+player_id;
    
          // Dropped the XHR_2 stuff here
          var xhr_2 = new XMLHttpRequest();
          var stats_return_text;
          stats_url = "https://na.api.pvp.net/api/lol/na/v1.3/stats/by-summoner/"+player_id+"/summary?season=SEASON2016&api_key=<THIS IS THE API KEY>";
    
          // CHANGED THIS TO BE XHR_2.onload -- IN HERE I KNOW XHR_1 IS ALREADY FINISHED
          xhr_2.onload = function(){
            if(xhr_2.status == 200) {
              stats_return_text = JSON.parse(xhr_2.responseText);
              demo.innerHTML += stats_return_text['playerStatsSummaries'].playerStatType;
            }
          };
    
          xhr_2.open("GET",stats_url, true);
          xhr_2.send();
        }
      };
      xhr.open('GET', name_url, true);
      xhr.send();
    
    });
    

    这几乎可以解决你所有的困境。

    关键是onload是一个回调,它在程序运行后很长时间内被触发,但xhr_2在您请求xhr_1的数据后立即触发(不是之后)它正在返回数据。)

    因此,player_id未定义。

    我们希望等到我们知道player_id之后,当我们回到xhr_1.onload的回调中时,我们知道我们已经有了(或者有些错误)。

    这非常令人困惑并且非常嵌套,虽然我认为Promise和异步函数/生成器是管理这种复杂性的绝佳解决方案,但这超出了这个范围;所以相反,我建议查看一些功能组合,以简化所有这些:

    function noop () { } // do nothing
    
    function getJSON (url, onload, onerror) {
      var xhr = new XMLHttpRequest();
      onload = onload || noop; // what I've been given or nothing
      onerror = onerror || noop; // " "
    
      xhr.onload = function () {
        var data;
        var error;
        try {
          // it's possible for parse to throw on malformed JSON
          data = JSON.parse(xhr.responseText);
        } catch (e) {
          error = e;
        }
    
        return error ? onerror(error) : onload(data); // fire one or the other (don't fall into the handler, if onload throws)
      };
      xhr.onerror = onerror;
    
      xhr.open("GET", url);
      xhr.send();
    }
    
    
    // localize URL construction
    function buildPlayerIdUrl (name) { return "https://______" + name + "_____"; } 
    function buildPlayerStatsUrl (id) { return "https://______" + id + "_____"; }
    
    
    // gets player by name and runs a function after the player has been loaded
    function getPlayer (player_name, done, error) {
      var id_url = buildPlayerIdUrl(player_name);
    
      function buildPlayer (response) {
        var player = response[player_name];
        return player;
      }
    
      function onload (response) {
        done(buildPlayer(response));
      }
    
      // Load the JSON, build the player, pass the player to done()
      getJSON(url, onload, error);
    }
    
    
    // get stats by player id and runs a function after the stats have been loaded
    function getPlayerStats (player_id, done, error) {
      var stats_url = buildPlayerStatsUrl(player_id);
    
      function buildStats (response) {
        var summary = response.playerStatsSummaries;
        return summary;
      }
      function onload (response) {
        done(buildStats(response));
      }
    
      // Load the JSON, build the stats, pass the stats to done()
      getJSON(stats_url, onload, error);
    }
    
    
    // perform a search by player name
    // note: All changes in step-number (1, 2, 3) are asynchronous,
    // and thus, must be nested in callbacks of some sort
    function search (player_name) {
      // Step 1: load the player
      getPlayer(playerName, function (player) {
        // Step 2a: update the DOM with the player name/id
        updatePlayerDom(player);
        // Step 2b: load the player stats
        getPlayerStats(player.id, function (stats) {
          // Step 3: update the DOM with the stats
          updateStatsDom(stats);
        });
      });
    }
    
    // player DOM update; keeping it nice and simple
    function updatePlayerDom (player) {
      document.querySelector(".Player-id").textContent = player.id;
      document.querySelector(".Player-name").textContent = player.name;
    }
    
    // stats DOM update; same as above
    function updateStatsDom (stats) {
      document.querySelector(".Player-stats").textContent = stats.playerStatType;
    }
    
    // bootstrap yourself to your UI
    some_button.onclick = function () {
      var player_name = some_input.value;
      search(player_name); // kick the whole thing off
    };
    

    这绝对是更多的代码,但是对每个单独的部分进行编辑也更简单,而不会踩到其他部分的脚趾。

    它(希望)也更容易看到所有部分的 _eventual timeline _ ,以及它们如何在search( )本身内流动。