У меня возникли проблемы с поиском каких-либо ресурсов для этого. Все, что мне нужно, это помощь в правильном направлении, чтобы получить что-то осязаемое для использования в HTML. Поэтому в основном, когда я вызываю console.log(keys), я не получаю объекты json в своей консоли, как я привык. Project специально просит сделать это через выборку.
function getFromSWAPI() {
fetch("https://swapi.dev/api/people/1")
.then(function (response) {
return response.json()
})
.then(function(data){
updateInfo(data)
})
.catch(function(err) {
console.warn(err)
})
}
const updateInfo = responseJSON => {
console.log(responseJSON.data)
let keys = Object.keys(responseJSON.data)
console.log(keys)
}
В этом коде есть несколько ошибок; только одна из них является непосредственной причиной проблем с ведением журнала, но все они должны быть исправлены, прежде чем это сработает.
Первый: почему не работает console.log / почему вы получаете ошибку TS «Невозможно преобразовать неопределенное или нулевое значение в объект в Function.keys»?
Потому что responseJSON
не имеет свойства с именем «данные», потому что ответ API не включает свойство с именем «данные». Я подозреваю, что это имя появляется здесь, потому что вы не понимаете, что такое HTTP-ответы и как работают промисы. Итак, давайте начнем с самого начала.
fetch
возвращает объект HTTP-ответ, внутри которого содержится некоторый текст. Вы получаете доступ к этому тексту, выполняя:
let text = await response.text()
Или, если вы используете связанные обработчики .then
(как в вашем образце), вы делаете следующее:
.then((response) => {
return response.text()
})
Если вы знаете, что текст является допустимым JSON (а вы это делаете), то вы можете извлечь текст и и разобрать его в значение с помощью одной операции: response.json()
(что вы и делаете).
Это возвращает обещание, содержащее значение, закодированное JSON. Если значение является объектом, оно будет иметь свойства, описанные этим JSON.
Какими свойствами будет обладать ваш объект? Откройте этот URL-адрес в своем браузере, и вы увидите их: «год_рождения», «создано», «отредактировано», «цвет_глаз», «фильмы», «пол», «цвет_волос», «рост», «родной мир», "масса", "имя", "цвет кожи", "виды", "звездолеты", "url", "транспортные средства".
«данные» не входят в этот список.
Вот что вы делаете с информацией из ответа:
.then(function (response) {
return response.json()
})
.then(function(data){
updateInfo(data)
})
Таким образом, вы передаете анализируемое значение непосредственно в функцию updateInfo
.
Затем функция updateInfo
пытается зарегистрировать свойство .data
полученного значения (которого не существует). То есть .data
есть undefined
.
Регистрация неопределенного объекта не является ошибкой. Но Object.keys
выкинет, если будет undefined
:
Object.keys(undefined)
//> Uncaught TypeError: can't convert undefined to object
Исправление заключается в удалении .data
как из оператора журнала, так и из вызова Object.keys
.
Второй:, это должен был быть ваш первый шаг отладки. Даже не понимая всего вышесказанного: если операции с точками данных, скрытыми внутри значения, не выполняются, наиболее очевидным первым шагом отладки является «сделать шаг назад» и попытаться изучить переменную, с которой вы работаете.
Чтобы проиллюстрировать: если console.log(myThing.items[0].parent.nodeName)
терпит неудачу, вы должны немедленно попробовать console.log(myThing)
— это позволяет вам проверить переменную myThing
, чтобы вы могли вручную проверить, является ли путь, к которому вы обращаетесь, законным. Одна из самых распространенных ошибок, которую совершают разработчики с любым уровнем опыта, заключается в том, что они указывают неверный путь к данным просто потому, что человеку свойственно ошибаться. (Typescript поможет вам заметить это во время написания кода, но вы должны научиться отслеживать проблемы без помощи инструмента, иначе вам всегда будет нужен этот инструмент.)
В третьих: Как я уже упоминал в первом черновике этого поста, вам не хватает некоторых утверждений return
.
Самое главное, что ваша getFromSWAPI
функция ничего return
не делает. Вы должны return
fetch
, если хотите, чтобы вызывающие абоненты получали данные.
function getFromSWAPI() {
return fetch("https://swapi.dev/api/people/1")
// ...rest of chained thens
Кроме того, вам нужно вернуть что-нибудь внутри обработчика .then
, где вы вызываете updateInfo
. То, что вы возвращаете, зависит от цели updateInfo
:
если предполагается, что updateInfo
изменяет необработанные данные API в интересах нижестоящего кода, вы должны вернуть результат его вызова:
.then(function(data){
return updateInfo(data)
})
если предполагается, что updateInfo
вызывает какой-то побочный эффект (например, обновление локального кеша необработанными данными или запуск события и т. д.), то вы можете «обойти» функцию: вызвать ее, но перенаправить исходное значение в нисходящий код:
.then(function(data){
updateInfo(data) // could do _anything_ with data
return data // passes the original data onward
})
Незапрошенный обзор кода
Вы определяете одну функцию, используя ключевое слово function
, а другую определяете как константную стрелочную функцию:
function getFromSWAPI() { /* stuff */ }
const updateInfo = responseJSON => { /* stuff */ }
Оба шаблона работают нормально, но вы должны стараться быть последовательными. Мой совет: если вы все еще изучаете JS, отдайте предпочтение ключевому слову function
, потому что оно более явное.
Предпочитайте использовать async/await вместо цепочек обработчиков.
Вы можете определить функции как async
, а затем await
Только конкретные операции, которые являются асинхронными. В вашем случае updateInfo
, похоже, не выполняет никакой асинхронной работы, поэтому отстойно, что он должен жить внутри этого обещания, состоящего из трех частей. Я бы пошел с этим:
async function getFromSWAPI() {
let response = await fetch("https://swapi.dev/api/people/1")
let data = await response.json()
updateInfo(data)
return data
}
starwars.js:24 TypeError: невозможно преобразовать undefined или null в объект в Function.keys (<анонимно>) в updateInfo (starwars.js:32:23) в starwars.js:21:16 (анонимно) @ starwars.js: 24 Promise.catch (асинхронный) getFromSWAPI @ starwars.js:23 это то, что я запускаю вот так
В данном случае это не проблема. Вопрос спрашивает, почему вызовы console.log
в обратных вызовах не регистрируют данные, которые ожидает спрашивающий.
Итак, в вашем коде есть небольшая ошибка,
В этой строке
{...}
.then(function (response) {
return response.json()
})
{...}
вы уже вернули json и, таким образом, получаете к нему доступ в следующей строке
{...}
.then(function (data) {
updateInfo(data)
})
{...}
Поскольку возвращенные данные сами по себе являются реальными данными, вам не нужно повторно обращаться к ним с помощью свойства данных здесь
{...}
const updateInfo = responseJSON => {
console.log(responseJSON.data)
let keys = Object.keys(responseJSON.data)
console.log(keys)
}
Готовый код будет выглядеть так -
function getFromSWAPI() {
fetch("https://swapi.dev/api/people/1")
.then(function (response) {
return response.json()
})
.then(function(data){
updateInfo(data)
})
.catch(function(err) {
console.warn(err)
})
}
const updateInfo = responseJSON => {
console.log(responseJSON)
let keys = Object.keys(responseJSON)
console.log(keys)
}
Alternatively, I would suggest you use async/await if you are using fetch inside a function.
Вы вызываете
updateInfo
с объектом данных, поэтомуresponseJSON
ЯВЛЯЕТСЯ данными. Итак, уберите.data
послеresponseJSON
.