JavaScript检查资源是否可通过fetch访问

时间:2017-03-24 09:24:25

标签: javascript html http asynchronous 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

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

5 个答案:

答案 0 :(得分:2)

你的chk函数返回undefined,你从promise回调中返回true / false,而不是从容器函数返回。

你应该在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)

答案 1 :(得分:2)

您无法在回调中返回。当你这样做时,它是返回的回调,而不是父函数。事实上,函数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'}); } 永远不会返回任何内容。

你想要做的是返回fetch返回的承诺。并试图取三次。

试试这个:

shell_exec("/usr/bin/ffmpeg -i video.mkv -r 20 -f image2pipe -vcodec ppm - | convert -delay 5 - output.gif");

答案 2 :(得分:2)

主要问题是你试图从回调中返回。这是没有意义的。 但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')
  })

答案 3 :(得分:2)

你的sleep函数是阻塞的,你真正想要的是一个递归函数,在检查url n次并延迟y秒等后返回一个promise。

像这样的东西

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上失败,任何回复都是成功的请求。

答案 4 :(得分:1)

试试这个,希望它有效

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) {
  ... 
});