javascript - 相邻依赖 AJAX(改进)

标签 javascript ajax html api google-chrome

这个问题是几天前发布的,但由于我是个小傻瓜,所以它充满了意大利面条代码之类的东西(也请原谅表单处理)除此之外,我添加了一些注释和给出了一些上下文,但问题仍然在于第二个 AJAX 调用。

这是 Chrome 抛出的错误“仅协议(protocol)方案支持跨源请求:http、data、chrome、chrome-extension、https、chrome-extension-resource。”

我隐藏了该 URL,因为它包含一个我不想共享的 API key 。

热烈欢迎任何和所有批评

/*
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>

最佳答案

所以你的主要错误是,如果你需要发出 CORS 请求(或者任何 AJAX 请求,实际上),你需要从服务器(甚至本地主机)运行代码。

如果您的页面协议(protocol)是“file:///”并且您试图从互联网加载内容(反之亦然),Google(和大多数浏览器)会对您感到抓狂。并且“file:///”也无法请求其他文件。

future 引用:您也无法从“https”页面发出“http”请求。

顺便说一句,第二个问题(被 CORS 安全性隐藏的问题)是您的 AJAX 请求现在正在并行运行。

为了使其按照您认为应该的方式工作(第一个返回后,运行第二个),您需要:

  1. 将与 xhr.onload 内的 xhr_2 相关的所有代码移至底部
  2. xhr.done 内的所有代码移至 xhr.onload 底部,并替换所有重复信息(并使用对直接返回结果)

这会导致类似的结果:

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

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

(希望)也可以更轻松地在 search( ) 本身内部查看所有部分的_事件时间线_以及它们如何流动。

关于javascript - 相邻依赖 AJAX(改进),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35974001/

相关文章:

javascript - 来自 DivPixelToLatLng 的 Google Maps API V3 不一致

python - Django - ajax_select 小部件

javascript - 无法使用ajax将Google map 从一个页面加载到另一个页面的div中

javascript - 发送ajax请求时如何过滤cookie?

javascript - 如何使用jquery从隐藏输入中获取值?

JavaScript onmousemove 显示 div 并跟随鼠标

javascript - 更改表格的边框和背景颜色并将鼠标悬停在它们上面

jquery - 将鼠标悬停在一个 div 上,移动另一个

javascript - 使用 jQuery 隐藏/取消隐藏列表元素

javascript - <br> 未附加到 div