JavaScript checking if resource is reachable with

2019-05-02 06:56发布

I'm basically just trying to verify if a resource is reachable from the executing client. I can not use XHR, because the target resource doesn't allow that.

I'm pretty new to JS and am currently working with this ( 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 */ } 
  }

I was expecting this code to check for the resource, print the result, then wait for a sec. Repeat this until 3 tries were unsuccessful or one of them was successful.

Instead the execution blocks for a while, then prints all of the console.logs at once and the resource is never reachable (which it is).

I do know that the fetch operation is asynchronous, but I figured if I previously declare done and implement a sleep it should work. In the worst case, the while loop would use the previously declared done.

How do I achieve the described behavior? Any advice is welcome.

5条回答
祖国的老花朵
2楼-- · 2019-05-02 07:21

The main problem is that you are trying to return from callback. That makes no sense. But fetch is Promise based request you can use Promise to simulate delays as well

Something like this should do the trick

// 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')
  })
查看更多
兄弟一词,经得起流年.
3楼-- · 2019-05-02 07:23

Your sleep function is blocking, what you really want is a recursive function that returns a promise after checking the url n times with a delay of y seconds etc.

Something like this

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);

    });
}

To be used like this

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

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

And note that this does not fail on 404 or 500, any response is a successful request.

查看更多
仙女界的扛把子
4楼-- · 2019-05-02 07:27

Try this, Hope it works

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) {
  ... 
});
查看更多
淡お忘
5楼-- · 2019-05-02 07:41

You can't return within a callback. When you do, it is the callback that is returning, not the parent function. If fact, the function chk is never returning anything.

What it sounds like you are intending to do is return the promise returned by fetch. And attempt to fetch three times.

Try this:

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'});
}
查看更多
时光不老,我们不散
6楼-- · 2019-05-02 07:43

Your chk function returns undefined, you return true/false from promise callbacks not from container function.

You should use recursion and timeout in catch callback. It will be something like this:

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)
查看更多
登录 后发表回答