在javascript中使用另一个fetch中的fetch

时间:2016-12-05 18:37:15

标签: javascript fetch-api

我想得到一个api,之后又打电话给另一个人。在javascript中明智地使用这样的代码吗?

fetch(url, {
 method: 'get',
 }).then(function(response) {  
  response.json().then(function(data) {  
    fetch(anotherUrl).then(function(response) {
      return response.json();
    }).catch(function() {
      console.log("Booo");
    });
  });  
}) 
.catch(function(error) {  
  console.log('Request failed', error)  
});

4 个答案:

答案 0 :(得分:40)

Fetch返回一个承诺,你可以chain multiple promises,并在第二个请求中使用第一个请求的结果:

该示例使用SpaceX API获取最新发射的信息,找到火箭的id,并获取火箭的信息。

var url = 'https://api.spacexdata.com/v2/launches/latest';

var result = fetch(url, {
    method: 'get',
  }).then(function(response) {
    return response.json(); // pass the data as promise to next then block
  }).then(function(data) {
    var rocketId = data.rocket.rocket_id;

    console.log(rocketId, '\n');
  
    return fetch('https://api.spacexdata.com/v2/rockets/' + rocketId); // make a 2nd request and return a promise
  })
  .then(function(response) {
    return response.json();
  })
  .catch(function(error) {
    console.log('Request failed', error)
  })

// I'm using the result variable to show that you can continue to extend the chain from the returned promise
result.then(function(r) {
  console.log(r); // 2nd request result
});
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:13)

嵌套fetch()来电没有问题。这取决于你试图通过嵌套调用来实现的目标。

您也可以使用.then()来锁定来电。另请参阅How to structure nested Promises

fetch(url)
.then(function(response) { 
  return response.json()
})
.then(function(data) {   
  // do stuff with `data`, call second `fetch`
  return fetch(data.anotherUrl)
})
.then(function(response) { 
  return response.json(); 
})
.then(function(data) {
  // do stuff with `data`
})
.catch(function(error) { 
  console.log('Requestfailed', error) 
});

答案 2 :(得分:4)

这是一个常见的问题,人们在开始使用Promises时会被绊倒,当我开始时,我自己就被包括在内。但是,首先......

很高兴你正在尝试使用新的Fetch API,但如果我是你,我现在会使用XMLHttpRequest实现,比如jQuery AJAX或Backbone重写的jQuery .ajax()实现,如果你已经在使用这些库。原因是因为Fetch API仍然是如此新颖,因此在此阶段进行实验。

话虽如此,人们肯定会使用它,但我不会在我自己的生产代码中,直到它处于“实验”状态。

如果您决定继续使用fetch,则可以使用polyfill注意:你必须跳过额外的箍以使错误处理正常工作,并从服务器接收cookie。如果您已经加载了jQuery,或者使用Backbone,那么现在就坚持使用它们;反正不是完全可怕的。

现在代码:

你想要一个平面结构,否则你就错过了Promises的观点。嵌套promises是不明智的,因为Promises解决了嵌套的异步回调(回调地狱)无法解决的问题。

通过简单地使用更易读的代码结构,您将节省时间和精力,并减少错误代码。这不是一切,但它可以说是游戏的一部分。

  

Promise是关于使异步代码保留大部分丢失的属性   同步代码,如扁平缩进和一个例外   信道。

     

- Petka Antonov(蓝鸟承诺图书馆)

// run async #1
asyncGetFn()
// first 'then' - execute more async code as an arg, or just accept results
// and do some other ops
.then(response => {
    // ...operate on response data...or pass data onto next promise, if needed
})
// run async #2
.then(asyncGetAnotherFn)
.then(response => {
    // ...operate on response data...or pass data onto next promise, if needed
})
// flat promise chain, followed by 'catch'
// this is sexy error handling for every 'then' above
.catch(err => {  
  console.error('Request failed', err) 
  // ...raise exeption...
  // ... or, retry promise... 
})

答案 3 :(得分:0)

<块引用>

在javascript中使用这样的代码是否明智?

是的。你的代码没问题。
除了在第二次请求之后, fetch(anotherUrl).then(function(response) {, 我会替换return response.json();response.json().then(function(data2) { – 就像在 第一个请求。
然后变量 data2 将包含内部响应主体 URL 请求,根据需要。
这意味着 – 无论您想用 data2 做什么,您都必须这样做 在第二个回调中(因为您没有返回承诺。)
此外,多打印几张将有助于了解正在发生的事情。

1.原始代码 - 稍作修改

进行这些更改后,这是一个包含您的堆栈片段 代码: 1

const url = 'https://jsonplaceholder.typicode.com/todos/1';
const anotherUrl = 'https://jsonplaceholder.typicode.com/todos/4';
fetch(url, {
  method: 'get'
}).then(function (response) {
  response.json().then(function (data) {
    console.log('Response body of outer "url":');
    console.log(JSON.stringify(data) + '\n\n');
    fetch(anotherUrl).then(function (response) {
      response.json().then(function (data2) {
        console.log('Response body of inner "anotherUrl":');
        console.log(JSON.stringify(data2) + '\n\n');
      });
    }).catch(function () {
      console.log('Booo');
    });
  });
})
.catch(function (error) {
  console.log('Request failed', error);
});
.as-console-wrapper { max-height: 100% !important; top: 0; }

这真的很好,虽然粗箭头样式更常见 这些天来定义一个函数。

2.代码重构

这是您代码的重构版本。 它有一个内部链式/嵌套请求 – fetch(urlInner) – 即 取决于从先前/外部请求中检索到的数据:fetch (urlOuter)
通过返回外部和内部 URL 获取的承诺, 稍后可以在代码中访问/解析承诺的结果: 2

const urlOuter = 'https://jsonplaceholder.typicode.com/todos/1';
let urlInner = '';
const resultPromise = fetch(urlOuter)
  .then(responseO => responseO.json())
  .then(responseBodyO => {
    console.log('The response body of the outer request:');
    console.log(JSON.stringify(responseBodyO) + '\n\n');
    const neededValue = responseBodyO.id + 3;
    urlInner = 'https://jsonplaceholder.typicode.com/todos/' + neededValue;
    console.log('neededValue=' + neededValue + ', URL=' + urlInner);
    return fetch(urlInner)
      .then(responseI => responseI.json())
      .then(responseBodyI => {
        console.log('The response body of the inner/nested request:');
        console.log(JSON.stringify(responseBodyI) + '\n\n');
        return responseBodyI;
      }).catch(err => {
        console.error('Failed to fetch - ' + urlInner);
        console.error(err);
      });
  }).catch(err => {
    console.error('Failed to fetch - ' + urlOuter);
    console.error(err);
  });

resultPromise.then(jsonResult => {
  console.log('Result - the title is "' + jsonResult.title + '".');
});
.as-console-wrapper { max-height: 100% !important; top: 0; }

请注意,缩进的深度不得超过八个空格。

3.这种代码风格的优点

这显然是一种嵌套编写代码的风格——这意味着 链式请求 fetch(urlInner) 缩进并在 第一个请求 fetch(urlOuter) 的回调。 然而,缩进树是合理的,这种风格引起了很好的共鸣 以我对链接请求的直觉。 – 但更重要的是, 这种风格使得编写错误消息成为可能 哪个网址失败

运行下面的代码片段以查看错误消息如何表明它是 导致错误的内部/第二个 URL

const urlOuter = 'https://jsonplaceholder.typicode.com/todos/1';
let urlInner = '';
const resultPromise = fetch(urlOuter)
  .then(responseO => responseO.json())
  .then(responseBodyO => {
    console.log('The response body of the outer request:');
    console.log(JSON.stringify(responseBodyO) + '\n\n');
    const neededValue = responseBodyO.id + 3;
    urlInner = 'https://VERY-BAD-URL.typicode.com/todos/' + neededValue;
    console.log('neededValue=' + neededValue + ', URL=' + urlInner);
    return fetch(urlInner)
      .then(responseI => responseI.json())
      .then(responseBodyI => {
        console.log('The response body of the inner/nested request:');
        console.log(JSON.stringify(responseBodyI) + '\n\n');
        return responseBodyI;
      }).catch(err => {
        console.error('Failed to fetch - ' + urlInner);
        console.error(err);
      });
  }).catch(err => {
    console.error('Failed to fetch - ' + urlOuter);
    console.error(err);
  });

resultPromise.then(jsonResult => {
  console.log('Result - the title is "' + jsonResult.title + '".');
});
.as-console-wrapper { max-height: 100% !important; top: 0; }

4.展平所有出现的 .then()?

受到他人的启发,您可能会试图将所有出现的 .then(),如下所示。

我会建议不要这样做——或者至少之前要三思 正在做。为什么?

  • 在没有错误的情况下,这无关紧要。
  • 如果有个错误,这样的风格会强制减少明显的错误 消息:

const urlOuter = 'https://jsonplaceholder.typicode.com/todos/1';
let urlInner = '';
const resultPromise = fetch(urlOuter)
  .then(responseO => responseO.json())
  .then(responseBodyO => {
    console.log('The response body of the outer request:');
    console.log(JSON.stringify(responseBodyO) + '\n\n');
    const neededValue = responseBodyO.id + 3;
    urlInner = 'https://VERY-BAD-URL.typicode.com/todos/' + neededValue;
    console.log('neededValue=' + neededValue + ', URL=' + urlInner);
    return fetch(urlInner);
  })
  .then(responseI => responseI.json())
  .then(responseBodyI => {
    console.log('The response body of the inner/nested request:');
    console.log(JSON.stringify(responseBodyI) + '\n\n');
    return responseBodyI;
  }).catch(err => {
    console.error('Failed to fetch one or more of these URLs:');
    console.log(urlOuter);
    console.log(urlInner);
    console.log(err);
  });
.as-console-wrapper { max-height: 100% !important; top: 0; }

代码很扁平,但最后捕获的错误无法决定 哪个失败的 URL 请求。


1 这个答案的所有片段都符合 JavaScript Semistandard Style
2 关于第 11 行 – return fetch(urlInner) – 它是 非常很容易忘记return提取。 (我曾经在写完这个答案之后忘记了它。) 如果您确实忘记了它,resultPromise 将不会包含任何承诺 全部。 代码段中的最后三行将失败——它们将输出 什么都没有。 结果完全失败!