为什么document.body null和我的readyState逻辑?

时间:2017-06-29 21:51:33

标签: javascript typescript iframe readystate domcontentloaded

我正在尝试尽快将iframe元素附加到document.body

错误报告涉及所有4种主要浏览器(Chrome,Safari,FF,IE - 各种版本),我们看到document.bodynull。我认为当我的JS文件被缓存并快速加载时会发生这种情况。

以下是插入iframe

的逻辑
private loadIFrame(): void {
  switch (document.readyState) {
    case 'uninitialized':
    case 'loading':
    case 'loaded':
      window.addEventListener('DOMContentLoaded',
        this.appendIFrame.bind(this)
      )
      break
    case 'interactive':
    case 'complete':
    default:
      this.appendIFrame()
  }
}

private appendIFrame(): void {
  if (document.getElementById('iframeId')) {
    return
  }

  let iFrame: HTMLIFrameElement = document.createElement('iframe')
  iFrame.src = document.location.protocol + this.ORIGIN + '/iframe.html'
  iFrame.id = 'iframeId'

  // document.body is null here
  document.body.appendChild(iFrame)
}

我很难在干净的环境中重现这个问题,这让我猜测这是如何在野外发生的。

我最初尝试使用此rreadyState逻辑,但在document.body状态下,我们在IE中看到undefinedloading

private loadIFrame(): void {
  switch (document.readyState) {
    case 'uninitialized':
    case 'loading':
      window.addEventListener('DOMContentLoaded',
        this.appendIFrame.bind(this)
      )
      break
    case 'loaded':
    case 'interactive':
    case 'complete':
    default:
      this.appendIFrame()
  }
}

我目前的质疑......

  1. 问题是default案例吗?我应该在那里添加事件监听器吗?我可以修改案例的顺序,以便事件监听器是默认的吗?
  2. body事件可能nullDOMContentLoaded吗?
  3. 是否可能有document.readyState的其他值正在落空?

2 个答案:

答案 0 :(得分:1)

首先,如果您已经检查了readyState并确定它是loaded,那么为什么要设置一个已经过去的事件处理程序(DOMContentLoaded )?

你可以这样做:

private loadIFrame(): void {
  switch (document.readyState) {
    case 'uninitialized':
    case 'loading':
    case 'loaded':
      this.appendIFrame.bind(this);
      break;
    case 'interactive':
    case 'complete':
    default:
      this.appendIFrame();
  }
}

接下来,您的事件处理程序注册是错误的。 .addEventListener() 有3个参数,第三个参数可以是两个值中的一个:

  1. 事件名称(字符串)
  2. 回调函数(引用或内联函数)

    3A。是否挂钩到捕获阶段(默认为布尔 - false

    3B。用于配置特征(对象)的选项对象

  3. 并且,addEventListener()本身会在将接收事件的对象上调用(在本例中为window)。

    应该是:

        window.addEventListener('DOMContentLoaded', function(){
          this.appendIFrame.bind(this);
        });
    

    另外(FYI),你真的应该手动插入你的语句结束分号而不是依赖于自动插入,因为存在导致错误的边缘情况。

答案 1 :(得分:0)

我更新了逻辑,我能够几乎消除错误,但当document.body为{{null时,我仍然看到readyStateinteractive 1}}。

一旦我评估导致问题的特定浏览器方案,我就会更新此帖子。

private loadIFrame(): void {
  switch (document.readyState) {
    case 'uninitialized':
    case 'loading':
    case 'loaded':
      document.addEventListener('DOMContentLoaded',
        this.appendIFrame.bind(this)
      )
      break
    case 'interactive':
    case 'complete':
    default:
      if(document.body) {
        this.appendIFrame()
      } else {
        window.addEventListener('load',
          this.appendIFrame.bind(this)
        )
      }
  }
}