2016-03-13 3 views
0

Этот вопрос был опубликован пару дней назад, но поскольку я - нуб, он был заполнен кодом спагетти и тому подобным (пожалуйста, извините за обработку формы). В стороне, я 'добавили некоторые примечания и дали некоторый контекст, но проблема все еще заключается в втором вызове AJAX.Adjacently Dependent AJAX (улучшенный)

Это ошибка, которую делает Chrome. «Запросы на кросс-начало поддерживаются только для схем протокола: http, data, chrome, chrome-extension, https, chrome-extension-resource».

Я скрыл URL-адрес, потому что он содержит ключ 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(){ 
 

 

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

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

 

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

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

 

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

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

+0

Ошибка должна быть достаточно ясной: 'https: URL.pre' не является допустимым URL-адресом, например,' https: // URL.pre', так что это, вероятно, просто опечатка. – adeneo

+0

Я исправлю это. На самом деле это опечатка в моем вопросе. Я не опубликовал настоящий URL. – JoshuaT

+1

Ошибка по-прежнему утверждает, что URL-адрес, который вы используете, не имеет действительного протокола * (для вызовов с перекрестным происхождением) *, поэтому с этим URL-адресом что-то не так, и вам будет сложно помочь, не зная * реальный * URL? – adeneo

ответ

1

Так ваша главная ошибка, что если вам нужно сделать CORS запросы (или любые запросы AJAX, на самом деле), вам нужно для запуска кода с сервера (даже локального).

Google (и большинство браузеров) будет беспокоиться о вас, если протокол вашей страницы «file: ///», и вы пытаетесь загрузить вещи из Интернета (или наоборот). И «file: ///» также не может делать запросы для других файлов.

Дальнейшая ссылка: вы также не можете делать запросы «http» со страницы «https».

Это вторая проблема (та, которая была скрыта системой безопасности CORS), заключается в том, что ваши запросы AJAX запускаются параллельно прямо сейчас.

Для того, чтобы сделать эту работу так, как вы думаете, он должен (после первого возвращения, запустить второй), вам нужно будет:

  1. двигаться весь код в нижней части , относящийся к xhr_2 внутри хода xhr.onload
  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.

Это становится ужасно запутанным и очень вложенным, и, хотя я думаю, что Promises и Async Functions/Generators - блестящие решения для управления этой сложностью, это выходит за рамки этого; так что вместо этого, я хотел бы предложить, глядя на какой-то функциональной композиции, чтобы упростить все это:

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().

+0

Какой замечательный ответ! Большое вам спасибо. Я многое узнаю от этого. Я бы хотел, чтобы я мог +10! эта платформа, поэтому я не могу на самом деле дать больше, чем галочку :( – JoshuaT

+0

Возможно, я чуть не обернул голову вокруг вашей концепции. Это, вероятно, было для вас не для вас, но для меня это было совершенно блестяще, и прекрасный вид на некоторые полезные функции программирования. Привет, хороший сэр. – JoshuaT

+0

Не беспокойтесь. И да, с небольшой практикой, становится легче писать чистые маленькие кусочки и подобные вещи. Удивительно, но по-прежнему редко можно найти людей, которые пишут производственный код так же аккуратно пути - не сказать, что я здесь написано безупречно; это не. Просто странно редко, учитывая, насколько гибкий JS.Когда вы будете готовы спуститься по кроличьей дыре, вы должны проверить карту/уменьшить, обещания, функции стрелок ES6 ... ... они могут взорвать ваш разум и заставить большую часть гнездо уйти – Norguard