Javascript fetch()故障转移URL

时间:2019-06-10 15:01:00

标签: javascript promise fetch

我有一个URL数组,我想执行一个fetch()请求:

const urls = [
  'https://dewnuf111111.com/configuration',
  'https://dewnuf222222.com/configuration',
  'https://bcsmania.co.uk/test.json'
];

如果抓取错误(例如,该网站不存在,内部错误等),我希望它尝试下一个URL,因此我添加了一个增量器。 一旦到达有效网址并成功发出请求,它就应该简单地console.log('DONE'),但我似乎无法使其正常工作。

这是我到目前为止编写的代码:

const urls = [
  'https://dewnuf111111.com/configuration',
  'https://dewnuf222222.com/configuration',
  'https://bcsmania.co.uk/test.json'
];

let obj = {a: 'test'};
let counter = 0;

function ajax(url) {
  // Check for for last URL in the array
  if (counter < urls.length) {
    return fetch(url)
      .then(response => {
        // Combine objects
        obj = Object.assign(obj, response.json());
        console.log(urls[counter], obj);
        return Promise.resolve(obj);
      }).catch(error => {
        counter++;
        // Fetch next URL
        ajax(urls[counter]);
      });
  }
}

function getConfigurations() {
  return ajax(urls[counter]);
}

getConfigurations().then((configurations) => {
  console.log('DONE', configurations);
});

这里是JSFiddle,用于预览。

有人能说出我可能要去哪里的地方吗? 我是否需要使函数async,然后使await成为结果?

3 个答案:

答案 0 :(得分:2)

您还需要在捕获中返回Promise,以便也可以从中进行链接:

.catch(error => {
    counter++;
    // return Fetch next URL
    return ajax(urls[counter]);
  });

答案 1 :(得分:1)

在这里,您正在将异步代码与同步代码混合在一起。由于您的循环本质上是同步的,因此它不会等待结果,并且一旦代码解析就打印完成。最简单的解决方案是,您可以使用async-await输入来循环url。我在下面给出了示例。请检查。

https://jsfiddle.net/gof91e6v/

const urls = [
  "https://dewnuf111111.com/configuration",
  "https://dewnuf222222.com/configuration",
  "https://bcsmania.co.uk/test.json"
];

let obj = { a: "test" };

async function getConfigurations(urls) {
  let result = null;
  if (counter < urls.length) {
    for (let count = 0, len = urls.length; count < len; count++) {
      try {
        result = await fetch(urls[count]);
      } catch (e) {}
      if (result) break;
    }
  }
  return result;
}

getConfigurations(urls).then(configurations => {
  console.log("DONE", configurations);
});

答案 2 :(得分:1)

我希望将获取网址列表与处理方式分开(例如您的Object.assign调用。)

在此版本中,fetchFirstWorking接受URL列表并响应Promise,该Promise将通过获取第一个实时URL的结果得到解决。请注意,它使用递归而不是计数器,因此将状态管理保持在最低水平。

getConfiguration保存业务逻辑。

const fetchFirstWorking = ( [url, ...urls], conf ) => url
  ? fetch (url, conf)
      .catch ( _ => fetchFirstWorking (urls) )
  : Promise .reject ('no urls could be loaded')

const getConfigurations = (urls) => 
  fetchFirstWorking(urls)
    .then ( res => res .json () )
    .then ( res => Object .assign ({a: 'test'}, res) )

const urls = [
  'https://dewnuf111111.com/configuration',
  'https://dewnuf222222.com/configuration',
  'https://bcsmania.co.uk/test.json'
]

getConfigurations (urls)
  .then(console.log)
  .catch(console.warn)

如果将最后一个URL替换为另一个虚拟对象,则会看到它生成控制台警告:

const fetchFirstWorking = ( [url, ...urls], conf ) => url
  ? fetch (url, conf)
      .catch ( _ => fetchFirstWorking(urls) )
  : Promise .reject ('no urls could be loaded')

const getConfigurations = (urls) => 
  fetchFirstWorking(urls)
    .then ( res => res .json () )
    .then ( res => Object .assign ({a: 'test'}, res) )

const urls = [
  'https://dewnuf111111.com/configuration',
  'https://dewnuf222222.com/configuration',
  'https://dewnuf333333.com/configuration',
]

getConfigurations (urls)
  .then(console.log)
  .catch(console.warn)