【问题标题】:how to consume JS promises when it is chained?链接时如何使用 JS 承诺?
【发布时间】:2020-08-16 20:01:29
【问题描述】:

在下面的代码中,为什么我在最后一行得到一个未定义的?如何编写以在变量 a 中获得响应

function getData(){
const url = "https://jsonplaceholder.typicode.com/users";
url2='https://jsonplaceholder.typicode.com/posts/'
fetch(url).then((res) =>{
  res.json().then((dataAsJson) => {
    return(dataAsJson[0].id);
  })
  .then((id)=>{
     fetch(url2+"/"+id).then((res)=> {
     return res.json().then((data) => {
      return(data);
    })
    })
})

})
}


var a = getData();
console.log(a)```

【问题讨论】:

标签: javascript promise fetch


【解决方案1】:

您缺少两个返回语句来实际将值从一个承诺传递到下一个承诺。因此,要使您的代码正常工作,您必须包含它们:

async function getData(){
  const url = "https://jsonplaceholder.typicode.com/users";
  url2='https://jsonplaceholder.typicode.com/posts/'
  const data = await fetch(url).then((res) =>{
    return res.json().then((dataAsJson) => {
      return(dataAsJson[0].id);
    })
  .then((id)=>{
     return fetch(url2+"/"+id).then((res)=> {
        return res.json().then((data) => {
          return(data);
        })
      })
    })
  })
}

这里还有一个提示:当从一个 Promise 返回时,它是另一个 Promise 还是一个简单的值都没有关系 - 下一个 then 调用总是会得到未包装的值。所以你实际上不必嵌套所有这些承诺调用。如果你这样写会更易读:

const url = "https://jsonplaceholder.typicode.com/users";
url2='https://jsonplaceholder.typicode.com/posts/'
const data = await fetch(url)
  .then((res) =>{ return res.json()})
  .then((dataAsJson) => { return(dataAsJson[0].id); })
  .then((id)=>{ return fetch(url2+"/"+id); })
  .then((res)=> { return res.json(); })

此外:由于您在每个回调中只返回一个值,因此您可以利用 JavaScript-Arrow-Function 功能,如果只有一个表达式,则自动返回并将其缩短为:

const url = 'https://jsonplaceholder.typicode.com/users';
url2 = 'https://jsonplaceholder.typicode.com/posts/';
const data = await fetch(url)
  .then(res => res.json())
  .then(dataAsJson => dataAsJson[0].id)
  .then(id => fetch(`${url2}/${id}`))
  .then(res => res.json());

这样可读性更好,错误更容易发现。 :)

更新:我完全忽略了在您的代码中,您正试图从异步 getData() 函数中同步读取。 @the spectre 在他的回答中澄清了这一点 - 所以这应该是公认的。但是,为了不让错误的代码存在,我将正确的行为编辑到我的答案中。

【讨论】:

    【解决方案2】:

    您应该能够使用await 简化该功能。 它消除了对嵌套回调的需要。此代码未经测试,但理论上应该可以工作。

    async function getData() {
      const url = "https://jsonplaceholder.typicode.com/users";
      const url2 = "https://jsonplaceholder.typicode.com/posts/";
    
      const firstFetch = await fetch(url)
      const firstResult = await firstFetch.json();
    
      const id = firstResult[0].id;
    
      const secondFetch = await fetch(url2 + "/" + id)
      return await secondFetch.json();
    }
    

    https://javascript.info/async-await

    您也可以创建一个新的承诺来解决您的第二次提取。但是这种方法比较麻烦

    【讨论】:

    【解决方案3】:

    由于您没有从 getData() 返回任何内容,因此您的定义是不确定的。

    Promise 及其链接方法 then()catch 将返回 Promise 本身的实例,而不是您从 then() 中的回调返回的数据。

    要获得您期望的行为,一种方法是使用asyncawait。捎带大卫,你会这样做:

    const url = 'https://jsonplaceholder.typicode.com/users';
    const url2 = 'https://jsonplaceholder.typicode.com/posts/';
    const data = await fetch(url)
      .then(res => res.json())
      .then(dataAsJson => dataAsJson[0].id)
      .then(id => fetch(`${url2}/${id}`))
      .then(res => res.json());
      
    console.log(data);

    【讨论】:

    • 对,我监督了那个。感谢您清除它 - 这应该是公认的答案!
    猜你喜欢
    • 2016-06-21
    • 1970-01-01
    • 2019-05-24
    • 2016-06-13
    • 2015-07-08
    • 2013-12-03
    • 2018-02-11
    • 1970-01-01
    • 2017-01-14
    相关资源
    最近更新 更多