代码之家  ›  专栏  ›  技术社区  ›  Ethan

服务工作者错误:事件已响应

  •  11
  • Ethan  · 技术社区  · 8 年前

    我一直遇到这个错误:

    Uncaught(in promise)DomeException:未能在“FetchEvent”上执行“respondWith”:事件已被响应。

    我知道,如果fetch函数中发生异步事件,服务人员会自动做出响应,但我无法确定这段代码中哪个位是违规者:

    importScripts('cache-polyfill.js');
    
    self.addEventListener('fetch', function(event) {
    
      var location = self.location;
    
      console.log("loc", location)
    
      self.clients.matchAll({includeUncontrolled: true}).then(clients => {
        for (const client of clients) {
          const clientUrl = new URL(client.url);
          console.log("SO", clientUrl);
          if(clientUrl.searchParams.get("url") != undefined && clientUrl.searchParams.get("url") != '') {
            location = client.url;
          }
        }
    
      console.log("loc2", location)
    
      var url = new URL(location).searchParams.get('url').toString();
    
      console.log(event.request.hostname);
      var toRequest = event.request.url;
      console.log("Req:", toRequest);
    
      var parser2 = new URL(location);
      var parser3 = new URL(url);
    
      var parser = new URL(toRequest);
    
      console.log("if",parser.host,parser2.host,parser.host === parser2.host);
      if(parser.host === parser2.host) {
        toRequest = toRequest.replace('https://booligoosh.github.io',parser3.protocol + '//' +  parser3.host);
        console.log("ifdone",toRequest);
      }
    
      console.log("toRequest:",toRequest);
    
      event.respondWith(httpGet('https://cors-anywhere.herokuapp.com/' + toRequest));
      });
    });
    
    function httpGet(theUrl) {
        /*var xmlHttp = new XMLHttpRequest();
        xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
        xmlHttp.send( null );
        return xmlHttp.responseText;*/
        return(fetch(theUrl));
    }
    

    任何帮助都将不胜感激。

    2 回复  |  直到 8 年前
        1
  •  19
  •   Jeff Posnick    8 年前

    问题是你的电话 event.respondWith() 在你的最高承诺之内 .then() 子句,这意味着它将在顶级承诺解析后异步执行。为了得到你期望的行为, 事件响应() 需要作为 fetch 事件处理程序的执行。

    你承诺中的逻辑有点难以遵循,所以我不确定你想要实现什么,但一般来说,你可以遵循以下模式:

    self.addEventListerner('fetch', event => {
      // Perform any synchronous checks to see whether you want to respond.
      // E.g., check the value of event.request.url.
      if (event.request.url.includes('something')) {
        const promiseChain = doSomethingAsync()
          .then(() => doSomethingAsyncThatReturnsAURL())
          .then(someUrl => fetch(someUrl));
          // Instead of fetch(), you could have called caches.match(),
          // or anything else that returns a promise for a Response.
    
        // Synchronously call event.respondWith(), passing in the
        // async promise chain.
        event.respondWith(promiseChain);
      }
    });
    

    这是总体思路。(如果你最终用 async / await .)

        2
  •  13
  •   Pier-Luc Gendreau    7 年前

    event.respondWith 必须同步调用,并且参数可以是返回解析为响应的承诺的任何内容。由于异步函数确实返回承诺,所以您所要做的就是将获取逻辑封装在异步函数中,该函数在某个时候返回响应对象和调用 和那个处理者。

    async function handleRequest(request) {
      const response = await fetch(request)
    
      // ...perform additional logic
    
      return response
    }
    
    self.addEventListener("fetch", event => {
      event.respondWith(handleRequest(event.request));
    });