有没有办法知道链接/脚本是否仍处于挂起状态或是否失败

时间:2016-10-03 05:13:13

标签: javascript html5 dom promise

我想从下面的html中了解,如果link[rel=import]link[rel=stylesheet]imgscript 待处理/已加载/失败/已中止< / strong>无需事先添加侦听器以及事件发生后的任何时刻

<!DOCTYPE html>
<html>
<head>
    <title>App</title>
    <meta charset="utf-8">
    <link rel="import" href="template-bundle.html">
    <link rel="stylesheet" href="bundle.css">
</head>
<body>
    <header><img src="logo.png" alt="App logo"></header>
    <!-- Boilerplate... -->
    <script src="./app-bundle.js"></script>
</body>
</html>

换句话说:是否有一个界面提供类似于Bluebird的isPending()isResolved()isRejected()方法或常规ES6承诺的界面?

奖金问题:这是否可以通过服务工作者来实现?

由于SW可以拦截请求并知道它们的状态,我想知道我是否可以实现一个返回Promise的API

    如果请求仍处于待处理状态,
  • 正在等待审核
  • 如果load事件已解雇,则
  • 已解决 如果erroraborted被解雇,
  • 将被拒绝。

感谢您的帮助

更新&amp;溶液

感谢@pritishvaidya和@ guest271314的答案,我能够使用MutationObserver提出一个可行的解决方案,该解决方案包括观察DOM以添加资源节点(链接,img,脚本)并添加一个承诺对于那些将如上所述解决的人

这很有效,只有在任何其他资源之前需要在<head>中内联脚本标记的caviat。 Here's an example

var resourceNodeSelector = 'link[href],script[src],img[src]';
function watchResource (n) {
    var url = n.href || n.src;

    if (!n.matches || !n.matches(resourceNodeSelector)) {
        return;
    }

    if (n.status) {
        return;
    }

    n.status = resourceObserver.promises[url] = new Promise(function (resolve, reject) {
        n.addEventListener('load', resolve);
        n.addEventListener('error', reject);
        n.addEventListener('abort', reject);
        n.addEventListener('unload', function (l) { delete resourceObserver.promises[url]} );
    });
    n.status.catch(function noop () {}); //catch reject so that it doesn't cause an exception
}

var resourceObserver = new MutationObserver(function (mutations) {
    document.querySelectorAll(resourceNodeSelector).forEach(watchResource);
});
resourceObserver.promises = {};
resourceObserver.observe(window.document, {childList: true, subtree: true});

一旦观察者到位,任何有效的资源元素都应该具有status promise属性,您可以在任何时间点检查

document.querySelector('link').status.then(linkLoaded).catch(linkFailed)

ServiceWorker应该可以实现更优雅的解决方案,不涉及使用昂贵的querySelectorAll,因为它可以编程为拦截并跟踪所有资源请求及其状态

2 个答案:

答案 0 :(得分:2)

您可以使用onload元素的onerror<link>个事件;请参阅右栏中的Browser CSS/JS loading capabilities

创建一个对象,以存储与<link>元素对应的所有Promise个请求以及已解决或被拒绝的<link>的状态。

Promise事件中拒绝onerror;使用.catch()链接到Promise.reject()来处理错误,以便Promise.all()不会停止处理作为参数传递的数组中已解析的promise。如果任何被拒绝的throw被拒绝在承诺数组中处理已解决的承诺,您还可以.catch() onerror处理程序Promise.all() Promise错误{/ 1}}。

window.onload事件处理程序中,使用Promise.all()处理所有已解析的链接,使用在window.onload事件之前调用的相同函数。 要等待Promise.all()的结果可用,请将src元素的<script>设置为bundle.js.then()链接到Promise.all()

<!DOCTYPE html>
<html>

<head>
  <title>App</title>
  <meta charset="utf-8">
  <script>
    var handleLinks = {
      links: [],
      isPending: true
    };

    function handleBeforeLoad() {
      if (document.querySelectorAll("link").length === 0) {   
        console.log("links loading state is pending..", handleLinks.isPending);
      } else {
        handleLinks.isPending = false;
        Promise.all(handleLinks.links)
          .then(function(linksContent) {
            console.log("links resolved:", linksContent
                       , "links loading state is pending.."
                       , handleLinks.isPending);
            linksContent.filter(Boolean).forEach(function(link) {
              // `content` property : html `document`,  `CSSStyleSheet` 
              // requested at `<link>` element
              console.log(link); 
            });
            // load `bundle.js`
            document.getElementById("bundle")
            .src = "bundle.js"

          })
          .catch(function(err) {
            console.log("link error:", err.message)
          })
      }
    }
    handleBeforeLoad();
    window.onload = handleBeforeLoad;

    function handleLink(el) {
      handleLinks.links.push(Promise.resolve({
        content: el.import || el.sheet,
        type: el.type,
        rel: el.rel,
        href: el.href,
        integrity: el.integrity,
        isResolved: true
      }));

    }

    function handleLinkError(el) {
      handleLinks.links.push(Promise.reject(new Error(JSON.stringify({
        error: "error loading link",
        type: el.type,
        rel: el.rel,
        href: el.href,
        integrity: el.integrity,
        isRejected: true
      }))).catch(function(err) {
        // handle error
        console.log(err);
        // this will return a resolved Promise
        return "error requesting link " + el.href;
        // `throw err` here if any rejected Promise should
        // stop `Promise.all()` from handling resolved Promise
      }));

    }
  </script>
  <link onload="handleLink(this)" 
        onerror="handleLinkError(this)" 
        rel="import" 
        href="template-bundle.html" 
        type="text/html">
  <link onload="handleLink(this)" 
        onerror="handleLinkError(this)" 
        rel="stylesheet" 
        href="bundle.css" 
        type="text/css">
  <!-- this should throw error, file does not exist -->
  <link onload="handleLink(this)" 
        onerror="handleLinkError(this)" 
        rel="stylesheet" 
        href="bundles.css" 
        type="text/css">

  <body>
    <header><img src="" alt="App logo"></header>
    <!-- Boilerplate... -->
    <script id="bundle"></script>
  </body>

</html>

plnkr http://plnkr.co/edit/DQj9yTDcoQJj3h7rGp95?p=preview

答案 1 :(得分:0)

是的,您可以在开发人员工具中查看此内容。右键单击网页并选择检查然后窗口将打开seleck网络选项,您可以在那里查看状态。