JavaScript: XMLHttpRequest возвращает строку «undefined» при первом запуске скрипта; Мне нужно, чтобы загрузить во время сценария - PullRequest
0 голосов
/ 02 мая 2020

Предисловие: я новичок в JS, у меня нет формального обучения этому, и я обычно делаю вещи на лету, исследуя то, что я пытаюсь сделать. Это не удалось на этот раз.

В настоящее время я пытаюсь сделать короткий JS скрипт, который будет служить букмарклетом. Намерение состоит в том, чтобы использовать API Tinder, чтобы показать пользователям Tinder некоторые из профильных изображений пользователей, которым они понравились, обычно доступные с функцией Gold.

В настоящее время это выглядит так:

var stringz;
var xhr = new XMLHttpRequest();
var tokez = localStorage.getItem("TinderWeb/APIToken");
var url = "https://api.gotinder.com/v2/fast-match/teasers?locale=en";
xhr.withCredentials = true;
xhr.open("GET", url);
xhr.setRequestHeader("accept", "application/json");
xhr.setRequestHeader("content-type", "application/json; charset=utf-8");
xhr.setRequestHeader("x-auth-token", tokez);
xhr.setRequestHeader("tinder-version", "2.35.0");
xhr.setRequestHeader("platform", "web");
xhr.send();
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        stringz = xhr.responseText;
        return stringz;
    }
};
//Turn the xhr response into a JSON string
var jasonstring = JSON.parse(stringz);
//Grab the URLs
var jasonstrung = jasonstring.data.results.map(x => x.user.photos.map(y => y.url));
//Turn the URLs into a nicely formatted JSON string
var jason = JSON.stringify(jasonstrung, null, 4);
//See what we got
console.log(jason);

Причина, по которой я выполняю JSON .parse и JSON .stringify, заключается в том, что возвращаемые данные из xhr представляют собой текст Строка отформатирована как JSON, но на самом деле это не JSON, поэтому мне нужно проанализировать ее, чтобы получить нужные фрагменты, а затем отформатировать их, чтобы они не были блоком goopy (хотя часть stringify не ' t супер необходимо)

При первом запуске этого в Chrome Dev Console выдается следующее:

VM5418:1 Uncaught SyntaxError: Unexpected token u in JSON at position 0
    at JSON.parse (<anonymous>)
    at <anonymous>:18:24

Мое предположение о том, почему это происходит, потому что stringz еще не «заполнен» и возвращается как «неопределенный», когда JSON .parse пытается его пробить.

Однако, как только сценарий завершится, если вы введете console.log(stringz), появится ожидаемая строка! Если запустить весь сценарий 2 раза, он напечатает окончательный требуемый набор данных:

[
    [
        "https://preview.gotinder.com/5ea6601a4a11120100e84f58/original_65b52a4a-e2b2-4fdb-a9e6-cb16cf4f91c6.jpeg"
    ],
    [
        "https://preview.gotinder.com/5a4735a12eced0716745c8f1/1080x1080_9b15a72b-10c3-47c6-8680-a9c1ff6bdbf7.jpg"
    ],
    [
        "https://preview.gotinder.com/5e8d4231370407010088281b/original_adb4a1e3-06c0-4984-bca1-978200a5a311.jpeg"
    ],
    [
        "https://preview.gotinder.com/5ea77de583887d0100f385b8/original_af32971d-6d80-4076-a0f8-92ab54f820b3.jpeg"
    ],
    [
        "https://preview.gotinder.com/5bf7a1a29c0764cc3409bb02/1080x1350_c9784773-b937-4564-8c96-1a380832fdab.jpg"
    ],
    [
        "https://preview.gotinder.com/5d147c0560364e16004bcf5e/original_bf550230-baba-4d70-8c75-da64a9ce1b6c.jpeg"
    ],
    [
        "https://preview.gotinder.com/5c9ca2c2c8a4501600a979aa/original_915f4c0f-eb58-4283-bc58-00fdadc3c33c.jpeg"
    ],
    [
        "https://preview.gotinder.com/541efb64f5d81ab67f4b599f/original_7f11dea4-41c8-4e9c-8c7a-0c886484a076.jpeg"
    ],
    [
        "https://preview.gotinder.com/5a8b56376c220c1f5d8b43d9/original_7c19a078-8bd7-48f9-8e30-123b8f937814.jpeg"
    ],
    [
        "https://preview.gotinder.com/5d0c18341ea6e416002bfb1d/original_41d203ce-d116-4714-a223-90ccfd928ff2.jpeg"
    ]
]

Есть ли способ заставить эту вещь работать в одном go (стиль букмарклета)? К сожалению, setTimeout не работает, если предположить, что для заполнения «stringz» требуется слишком много времени, прежде чем я использую JSON .parse.

Спасибо!

1 Ответ

0 голосов
/ 02 мая 2020

Проблема в том, что XHR делает вашу функцию асинхронной: она отправляет запрос, а ответ приходит позже - в течение этого времени ваши следующие (и следующие, и следующие, ....) строки код выполняется.

Вы должны начать преобразование строки JSON, когда ответ уже получен - это означает, что вы должны поместить свой код xhr.onreadystatechange (мне пришлось закомментировать много вещей, так что фрагмент работает):

var stringz;
var xhr = new XMLHttpRequest();
// var tokez = localStorage.getItem("TinderWeb/APIToken");
// var url = "https://api.gotinder.com/v2/fast-match/teasers?locale=en";
var url = "https://jsonplaceholder.typicode.com/posts";
// xhr.withCredentials = true;
xhr.open("GET", url);
// xhr.setRequestHeader("accept", "application/json");
// xhr.setRequestHeader("content-type", "application/json; charset=utf-8");
// xhr.setRequestHeader("x-auth-token", tokez);
// xhr.setRequestHeader("tinder-version", "2.35.0");
// xhr.setRequestHeader("platform", "web");

xhr.onreadystatechange = function() {
  if (this.readyState == 4 && this.status == 200) {
    // the response arrives here
    stringz = this.responseText;

    // start your JSON transformation when the
    // response arrives
    jsonTransform(stringz)
    return stringz;
  }
};

xhr.send();

// this part of code will be executed synchronously - this
// doesn't wait until your response arrives
var synchronous = 'this will be logged before response arrives'

console.log(synchronous)

function jsonTransform(stringz) {
  //Turn the xhr response into a JSON string
  var jasonstring = JSON.parse(stringz);
  //Grab the URLs
  // var jasonstrung = jasonstring.data.results.map(x => x.user.photos.map(y => y.url));
  //Turn the URLs into a nicely formatted JSON string
  // var jason = JSON.stringify(jasonstrung, null, 4);
  //See what we got
  const jason = JSON.stringify(jasonstring)
  console.log(jason);
}

Другой метод

Я предлагаю вам использовать fetch() вместо xhr - с xhr вы должны позаботиться обо всем - fetch() является довольно новым, с синтаксисом на основе Promise (вы будете много встречаться, если будете работать с API)

Подробнее о fetch():

const url = "https://jsonplaceholder.typicode.com/posts";

// fetch returns a Promise, so you can use
// .then, .catch, .finally - very handy!
fetch(url)
  .then(resp => {
    return resp.json()
  })
  .then(json => {
    // you have the json formatted response here:
    console.log(json)
  })
  .catch(err => {
    console.log(err)
  })

Вы можете использовать fetch() с дружественным asyn c -wait синтаксисом, который делает ваш код синхронным:

const url = "https://jsonplaceholder.typicode.com/posts";

// await can only be placed in an async function!
async function fetchAPI(url) {
  // try-catch block to handle errors of the fetch()
  try {
    const response = await fetch(url)
    const json = await response.json()
    console.log(json)
  } catch (err) {
    console.log(err)
  }
}

fetchAPI(url)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...