`window.onload` 可以做到容错吗?有更好的替代方案吗?

huangapple go评论75阅读模式
英文:

Can `window.onload` be made fault-tolerant? Is there a better alternative?

问题

我正在创建一个包含多个嵌入的GeoGebra文件的网页。这意味着对于每个GeoGebra applet,我在<body>中都有一个关联的<div>元素,以及一个用于配置它的关联脚本;在<body>的末尾,我有以下脚本,将所有applet添加到它们关联的<div>中:

<script>
	window.onload = function() {
		applet_0.inject('ggb-element-0');
		applet_1.inject('ggb-element-1');
		applet_2_NoLimit.inject('ggb-element-2-NoLimit');
		applet_2_YesLimit.inject('ggb-element-2-YesLimit');
		applet_3.inject('ggb-element-3');
		applet_4_Flat.inject('ggb-element-4-Flat');
		applet_4_Faster.inject('ggb-element-4-Faster');
	};
</script>

我注意到,如果脚本的前六行中的任何一行失败,例如,如果关联的文件无法加载,那么在失败的行之后的所有行都不会执行。

我想要使这个工作,即使某个嵌入出现问题。我已经发现我不能有多个window.onload命令(只有最后一个会执行)。是否有另一种方法可以使这个更容忍错误?

英文:

I am creating a webpage with multiple GeoGebra files embedded in it. That means I have, for each GeoGebra applet, a &lt;div&gt; element in the &lt;body&gt; with an associated script to configure it; and at the end of the &lt;body&gt; I have the following script that adds all the applets to their associated &lt;div&gt;s:

&lt;script&gt;
	window.onload = function() {
		applet_0.inject(&#39;ggb-element-0&#39;);
		applet_1.inject(&#39;ggb-element-1&#39;);
		applet_2_NoLimit.inject(&#39;ggb-element-2-NoLimit&#39;);
		applet_2_YesLimit.inject(&#39;ggb-element-2-YesLimit&#39;);
		applet_3.inject(&#39;ggb-element-3&#39;);
		applet_4_Flat.inject(&#39;ggb-element-4-Flat&#39;);
		applet_4_Faster.inject(&#39;ggb-element-4-Faster&#39;);
	};
&lt;/script&gt;

I noticed that if any of the first six lines of the script fails, for example if the associated file cannot be loaded, all lines following the failed line are not executed.

I want to make this work even if something goes wrong for one of the embeddings. I already discovered that I can't have multiple window.onload commands (only the last one is executed). Is there an alternative way to make this more fault-tolerant?

答案1

得分: 4

多个加载事件处理程序

您可以通过调用window.addEventListener而不是设置window.onload来拥有多个加载事件监听器。以这种方式添加的监听器按照添加的顺序执行。通过将第三个参数设置为{once: true},事件监听器将在调用后自动移除。这些监听器可以在代码中的任何位置添加,只要在您认为合适的加载事件之前添加即可。

例如,前两个监听器可以通过以下方式添加:

addEventListener('load', () => applet_0.inject('ggb-element-0'), {once: true});

//...

addEventListener('load', () => applet_2_NoLimit.inject('ggb-element-2-NoLimit'), {once: true});

// 等等...

单个load事件处理程序

或者,如果您想要使用单个加载事件处理程序,比如以一致的方式报告错误,您可以重新构造代码,将 applet 和字符串参数提供给一个单一函数,在try/catch结构内进行注入,例如:

addEventListener("load", event => {
    [
      [applet_0, 'ggb-element-0'],
      [applet_1, 'ggb-element-1'],
      [applet_2_NoLimit, 'ggb-element-2-NoLimit'],
      [applet_2_YesLimit, 'ggb-element-2-YesLimit'],
      [applet_3, 'ggb-element-3'],
      [applet_4_Flat, 'ggb-element-4-Flat'],
      [applet_4_Faster, 'ggb-element-4-Faster'],
    ]
    .forEach(args => {
      const [applet, selector] = args;
      try {
        applet.inject(selector);
      }
      catch(err) {
        console.log(`injection of ${selector} into applet failed:`, err);
      }
    })
  },
  {once: true}
);

如果您对const [applet, selector] = args;语法不熟悉,请参阅解构赋值语法 在 MDN 上的说明。

英文:

Multiple load event handlers

You can have multiple load event listeners by calling window.addEventListener instead of setting window.onload. Listeners added in this way are executed in the order they are added. By providing {once: true} as the third argument the event listener will be removed automatically after being called. The listeners can be added anywhere in code before the load event has been fired that you deem appropriate.

For example the first two listeners could be added by

addEventListener(&#39;load&#39;, ()=&gt; applet_0.inject(&#39;ggb-element-0&#39;), {once: true});

 //...

addEventListener(&#39;load&#39;, ()=&gt; applet_2_NoLimit.inject(&#39;ggb-element-2-NoLimit&#39;), {once: true});

// etc...

Single load event handler

Alternatively if you want to use a single load event handler, say to report errors in a consistent fashion, you could refactor the code to supply applet and string arguments to a single function that does the injection within a try/catch construct, as for example:

addEventListener( &quot;load&quot;, event =&gt; {
    [
      [ applet_0, &#39;ggb-element-0&#39;],
      [ applet_1, &#39;ggb-element-1&#39;],
      [ applet_2_NoLimit, &#39;ggb-element-2-NoLimit&#39;],
      [ applet_2_YesLimit, &#39;ggb-element-2-YesLimit&#39;],
      [ applet_3, &#39;ggb-element-3&#39;],
      [ applet_4_Flat, &#39;ggb-element-4-Flat&#39;],
      [ applet_4_Faster, &#39;ggb-element-4-Faster&#39;],
    ]
    .forEach( args=&gt; {
      const [applet, selector] = args;
      try {
        applet.inject(selector);
      }
      catch(err) {
        console.log(`injection of ${selector} into applet failed:`, err);
      }
    })
  },
  {once: true}
);

If you are unfamiliar with the const [applet, selector] = args; syntax please see destructuring assignment syntax on MDN.

huangapple
  • 本文由 发表于 2023年7月28日 05:57:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76783651.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定