【问题标题】:How do I choose the best URL to fetch?如何选择要获取的最佳 URL?
【发布时间】:2018-02-19 09:43:21
【问题描述】:

我正在一组 URL 中寻找最佳 URL(比如本地缓存): ['https://1.2.3.4', 'https://httpbin.org/delay/3', 'https://httpbin.org/status/500'] 并选择具有5 秒超时。否则回退到“https://httpbin.org/status/200”。在这个人为的例子中,'https://httpbin.org/delay/3' 应该获胜!

function fallback(response) {
  if (response.ok) {
    return response;
  }
  console.log("Trying fallback")
  return fetch("https://httpstat.us/200") // absolute fallback
}

var p = Promise.race([
    fetch('https://1.2.3.4'), // will fail
    fetch('https://httpbin.org/delay/3'), // should be the winner
    fetch('https://httpbin.org/status/500'), // will fail
    new Promise(function(resolve, reject) { // Competing with a timeout
      setTimeout(() => reject(new Error('request timeout')), 5000)
    })
  ])
  .then(fallback, fallback)
  .then(console.log)

我的代码存在Promise race 在任何返回时结束的问题。我怎样才能最好地构建它,以便“https://httpbin.org/delay/3”正确地赢得比赛?

【问题讨论】:

  • 当你说“将失败”时,你的意思是承诺拒绝吗?
  • 不,除非服务器无法访问,否则承诺应该始终成功。发生的情况是服务器响应但状态不是 200,因此不是有效的端点。

标签: javascript promise fetch


【解决方案1】:

Promise.race([
  new Promise(resolve => {
    const ignoreError = () => {}
    // first to resolve with .ok gets to resolve the promise
    const resolveIfOk = res => res.ok && resolve(res)
    fetch('https://httpbin.org/delay/20').then(resolveIfOk, ignoreError)
    fetch('https://httpbin.org/delay/3').then(resolveIfOk, ignoreError)
    fetch('https://1.2.3.4').then(resolveIfOk, ignoreError)
    return;
  }),
  new Promise((_, reject) => setTimeout(() => reject(new Error('timed out')), 4000)) // reject if timeout
]).then(function(value) {
  console.log("Success", value);
  return value
}, function(reason) {
  console.log("Going to use fallback", reason);
  return fetch('https://httpstat.us/200')
}).then(console.log)

解决方案来自https://twitter.com/secoif

【讨论】:

    【解决方案2】:

    function race(promises) {
      return Promise.race(Object.keys(promises).map((key) => {
          return promises[key]
        }))
        .then(function(response) {
          console.log(response);
          if (!response.ok) {
            delete promises[response.url];
            return race(promises)
          } else if (Object.keys(promises).length == 0 || response.url == 'timeout') {
            console.log('returning default');
            return fetch("https://httpstat.us/200")
          }
    
          return response;
        })
    }
    
    race({
      'https://1.2.3.4': fetch('https://1.2.3.4'),
      'https://1.2.3.4': fetch('https://1.2.3.4'),
      'timeout': new Promise(function(resolve, reject) {
        setTimeout(() => reject(new Error('request timeout')), 5000)
      })
    }).then(function(response) {
      console.log(response)
    }).catch(function(err) {
      console.log('err:');
      console.log(err.message)
      return fetch("https://httpstat.us/200")
    }).then(function(defaultFetch) {
      console.log('timed out requesting failed urls, getting default:');
      console.log(defaultFetch);
    });

    【讨论】:

    • 而不是像 500 这样的特定错误,而是测试 !response.ok。你也可以插入一个 sn-p 以便它可以运行吗? :)
    • 插入sn-p
    • 这很接近,但如果全部失败,则不会尝试回退
    • 编辑过的原始sn-p.
    • 我认为不需要键值测试结构。 Object.keys 在我看来很难看!来看看httpbin.org/delay/3 是如何获胜的??
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-28
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-31
    • 2011-12-30
    相关资源
    最近更新 更多