JavaScript 检查资源是否可以通过获取访问

JavaScript checking if resource is reachable with fetch

我基本上只是想验证是否可以从正在执行的客户端访问资源。我不能使用 XHR,因为目标资源不允许这样做。

我是 JS 的新手,目前正在使用它 (executable here):

    var done = false;
    var i = 1;
    var t = "https://i.stack.imgur.com/Ya15i.jpg";

    while(!done && i < 4)
    {
      console.log("try "+i);

      done = chk(t);
      sleep(1000);

      i = i+1;

      if (done)
      {
        console.log("Reachable!");
         break;
      }
      else
      {
         console.log("Unreachable.");
      }
    }

  function chk(target)
  {
    console.log("checking "+target)
    fetch(target, {mode: 'no-cors'}).then(r=>{
    return true;
    })
    .catch(e=>{
    return false;
    });
  }

  // busy fake sleep
  function sleep(s)
  {
      var now = new Date().getTime();
      while(new Date().getTime() < now + s){ /* busy sleep */ } 
  }

我原以为这段代码会检查资源,打印结果,然后等待一秒钟。重复此操作,直到 3 次尝试不成功或其中一次成功。

相反,执行会阻塞一段时间,然后立即打印所有 console.logs 并且资源永远无法访问(它是)。

我知道 fetch 操作是异步的,但我认为如果我之前声明 done 并实现睡眠,它应该可以工作。在最坏的情况下,while 循环将使用先前声明的 done.

如何实现所描述的行为?欢迎任何建议。

试试这个,希望它有效

var myHeaders = new Headers();
myHeaders.append('Content-Type', 'image/jpeg');

var myInit = { method: 'GET',
               headers: myHeaders,
               mode: 'no-cors',
               cache: 'default' };

var myRequest = new Request('https://i.stack.imgur.com/Ya15i.jpg');

fetch(myRequest,myInit).then(function(response) {
  ... 
});

您的 chk 函数 return 未定义,您 return true/false 来自 promise 回调而不是来自容器函数。

你应该在 catch 回调中使用递归和超时。 它将是这样的:

var i = 0;
var done = false;
var t = "https://i.stack.imgur.com/Ya15i.jpg";
(function chk(target){
  console.log("checking "+target)
  fetch(target, {mode: 'no-cors'}).then(r=>{
   done = true;
   console.log("Reachable!");
  })
  .catch(e=>{
   console.log("Unreachable.");
   if(i<4){
     setTimeout(function(){
       chk(target)
     },1000)
   }
  });
})(t)

您不能 return 在回调中。当您这样做时,returning 是回调,而不是父函数。事实上,函数 chk 永远不会 returning 任何东西。

听起来您打算做的是 return 由 fetch return 承诺。并尝试获取三次。

试试这个:

const numberOfTries =3;
currentTry = 1;
var t = "https://i.stack.imgur.com/Ya15i.jpg";

chk(t);

function tryCheck(resource, currentTry) {
  chk(resource).done(function(){
    console.log("Reachable!");
  }).catch(function(e) {
    console.log("Unreachable.");
    if (currentTry >= numberOfTries) return;
    sleep(1000);
    tryCheck(resource, currentTry + 1);
  });
}

function chk(resource) {
  console.log("checking "+target);
  return fetch(target, {mode: 'no-cors'});
}

主要问题是您正试图 return 从回调中。这是没有意义的。 但是 fetch 是基于 Promise 的请求,您也可以使用 Promise 来模拟延迟

像这样应该可以解决问题

// promise based delay
const delay = timeout => new Promise(resolve => setTimeout(resolve, timeout))

// check if target can be fetched
const check = target => fetch(target, {...})
    .then(response => response.ok)

const ping = (target, times = 3, timeout = 1000) => check(target)
  .then(found => {
    if(!found && times) { // still can check
      // wait then ping one more time
      return delay(timeout).then(() => ping(target, times - 1, timeout))
    }

    return found
  })

ping('https://i.stack.imgur.com/Ya15i.jpg')
  .then(found => {
    console.log(found ? 'Reachable': 'Unreachable')
  })

你的 sleep 函数正在阻塞,你真正想要的是一个递归函数,returns 在检查 url n 次后延迟 returns 的承诺 y秒等等

像这样

function chk(target, times, delay) {
    return new Promise((res, rej) => {                       // return a promise

        (function rec(i) {                                   // recursive IIFE
            fetch(target, {mode: 'no-cors'}).then((r) => {   // fetch the resourse
                res(r);                                      // resolve promise if success
            }).catch( err => {
                if (times === 0)                             // if number of tries reached
                    return rej(err);                         // don't try again

                setTimeout(() => rec(--times), delay )       // otherwise, wait and try 
            });                                              // again until no more tries
        })(times);

    });
}

这样使用

var t = "https://i.stack.imgur.com/Ya15i.jpg";

chk(t, 3, 1000).then( image => {
    console.log('success')
}).catch( err => {
    console.log('error')
});

请注意,这不会在 404 或 500 上失败,任何响应都是成功的请求。