尝试通过 js 使用 fetch。它正在返回,就好像它实际上没有调用任何数据一样。我哪里错了?

Trying to use fetch via js. It's returning as if its not actually calling any data. Where am I going wrong?

我无法为此找到任何资源。我所需要的只是在正确的方向上得到帮助,以便在某些 HTML 中使用一些有形的东西。所以基本上当我调用 console.log(keys) 时,我不会像以前那样在我的控制台中得到 json 对象。 Project 特别要求通过 fetch 以这种方式完成。

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

这段代码有几处错误;其中只有一个是您在日志记录方面遇到问题的直接原因,但在这起作用之前,它们都需要修复。

First:为什么 console.log 不起作用/为什么会出现 TS 错误“无法将未定义或 null 转换为 Function.keys 处的对象”?

因为 responseJSON 没有名为“数据”的 属性,因为 API 响应不包含名为“数据”的 属性。我怀疑该名称出现在这里是因为您对什么是 HTTP 响应以及 Promise 的工作方式感到困惑。那么让我们从头开始吧。

fetch returns 一个 HTTP Response 对象,其中包含一些文本。您可以通过以下方式访问该文本:

let text = await response.text()

或者,如果您使用链式 .then 处理程序(如您的示例中所示),您可以这样做:

.then((response) => {
    return response.text()
})

如果您知道文本是有效的 JSON(并且您知道),那么您可以提取文本 通过一次操作将其解析为一个值: response.json() (这就是你正在做的)。

这 return 是一个包含由 JSON 编码的值的 Promise。如果该值是一个对象,它将具有 JSON.

描述的属性

您的对象将具有哪些属性?在浏览器中打开 URL,您会看到它们:“birth_year”、“created”、“edited”、“eye_color”、“films”、“gender”、 "hair_color", "height", "homeworld", "mass", "name", "skin_color", "species", "starships", "url", "车辆".

“数据”不在该列表中。

这就是您使用响应中的信息所做的事情:

.then(function (response) {
    return response.json()
})
.then(function(data){
    updateInfo(data)
})

因此,您将解析后的值直接传递给 updateInfo 函数。

updateInfo 函数然后尝试在接收到的值(不存在)上记录 .data 属性。即.dataundefined.

记录未定义的对象不是错误。但是 Object.keys 如果提供 undefined:

将会抛出
Object.keys(undefined)
//> Uncaught TypeError: can't convert undefined to object

修复方法是从日志语句和 Object.keys 调用中删除 .data

其次: 这应该是您调试的第一步。即使不理解以上所有内容:如果对隐藏在值中的数据点的操作失败,最明显的第一个调试步骤是“后退一步”并尝试检查您正在使用的变量。

举例说明:如果 console.log(myThing.items[0].parent.nodeName) 失败,您应该立即尝试 console.log(myThing) -- 这允许您检查 myThing 变量,以便您可以手动验证您的路径是否正确访问是合法的。所有经验水平的开发人员最常犯的错误之一是他们放入了错误的数据路径,仅仅是因为犯错是人之常情。 (Typescript 会帮助您在编写代码时注意到这一点,但您必须学会如何在没有工具帮助的情况下跟踪问题,否则您将始终需要该工具。)

第三: 正如我在本 post 的初稿中提到的,您遗漏了一些 return 语句。

最重要的是,您的 getFromSWAPI 函数不会 return 任何东西。如果您希望呼叫者接收数据,您必须 return fetch

function getFromSWAPI() {
    return fetch("https://swapi.dev/api/people/1")
    // ...rest of chained thens

此外,您需要在调用 updateInfo.then 处理程序中 return 一些东西 。你 return 取决于 updateInfo 的目的是什么:

  • 如果 updateInfo 应该为了下游代码修改原始 API 数据,那么您应该 return 调用它的结果:

    .then(function(data){
        return updateInfo(data)
    })
    
  • 如果 updateInfo 应该引起某种 side-effect(比如用原始数据更新本地缓存,或触发事件等),那么你可能想“绕过”函数:调用它,但将原始值转发给下游代码:

    .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 似乎没有做任何异步工作,所以它必须生活在这个 three-part 链式承诺中有点糟糕。我会这样做:

    async function getFromSWAPI() {
        let response = await fetch("https://swapi.dev/api/people/1")
        let data = await response.json()
        updateInfo(data)
        return data
    }
    

基本上你的代码中有一个小错误,

在这一行

{...}
.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.