如何判断<script>标签是否加载失败


111

我正在向<script>页面的中动态添加标签<head>,并且我想知道加载是否以某种方式失败-404,加载的脚本中的脚本错误等。

在Firefox中,这有效:

var script_tag = document.createElement('script');
script_tag.setAttribute('type', 'text/javascript');
script_tag.setAttribute('src', 'http://fail.org/nonexistant.js');
script_tag.onerror = function() { alert("Loading failed!"); }
document.getElementsByTagName('head')[0].appendChild(script_tag);

但是,这在IE或Safari中不起作用。

有谁知道在Firefox以外的浏览器中实现此目的的方法吗?

(我认为不需要在.js文件中放置特殊代码的解决方案是一个很好的解决方案。这种解决方案既笨拙又不灵活。)


4
大网站,自动加载通过ajax加载的内容的依赖项。if+ polling令人讨厌,我不想将其纳入所有JS。
大卫,

2
您可能还想在使用脚本标记注入发出JSONP请求时检查加载失败...
schellsan 2012年

Answers:


36

脚本标签没有错误事件。您可以告诉它何时成功,并假设它在超时后尚未加载:

<script type="text/javascript" onload="loaded=1" src="....js"></script>

7
即使出现JavaScript错误,也会触发“ onload”监听器。
卡·马太斯

38
好吧,是的,如果文件LOADS并且文件本身有错误,但是如果文件没有送达,则onload将永远不会触发。
Diodeus-James MacFarlane,

1
是的,是的,这就是为什么我要求更具体地说明他正在寻找哪种错误。
卡·马太斯

1
但是超时必须由页面的编码器提供,对吗?因此,编码人员可能会选择与浏览器不同的超时时间,并假定脚本加载超时,然后稍后再使脚本成功执行。或不?
hippietrail 2011年

6
脚本标签有onerror evnt。找不到资源时将触发。
Nguyen Tran

24

如果您只关心html5浏览器,则可以使用错误事件(因为这仅用于错误处理,应该可以在KISS IMHO的下一代浏览器中仅支持此功能)。

从规格:

如果src属性的值为空字符串,或者无法解析,则用户代理必须将任务排队以在元素上触发一个名为error的简单事件,然后中止这些步骤。

如果加载导致错误(例如DNS错误或HTTP 404错误),则执行脚本块必须仅在元素上触发一个名为error的简单事件。

这意味着您不必进行任何易于出错的轮询,并且可以将其与async和defer属性结合使用,以确保脚本不会阻止页面呈现:

即使指定了async属性,也可以指定defer属性,以使仅支持defer(而不支持async)的旧版Web浏览器退回到defer行为,而不是默认的同步阻止行为。

有关http://www.w3.org/TR/html5/scripting-1.html#script的更多信息


1
对JSONP实现(例如jQuery中的支持)有任何想法吗?我在此处阅读的有关检测JSONP加载失败的所有内容均表示无法检测到该错误,但可以使用超时来解决,并将超时添加到了最新版本的JSONP中。似乎这个答案提供了比超时更好的东西-是正确的吗?
hippietrail 2011年

1
例子可能吗?
rogerdpack

13
<script src="nonexistent.js" onerror="alert('error!')"></script> 小提琴
Rudey '17

@Rudey Uncaught SyntaxError: Unexpected token '<'(最新版Chrome浏览器)
daleyjem

@daleyjem听起来好像您已尝试将HTML标签放入JavaScript中。<script src="nonexistent.js" onerror="alert('error!')"></script>应该放在您的HTML文件中,而不是JS中。
鲁迪(Rudey)

21

Erwinus的脚本效果很好,但是编码却不太清楚。我自由地清理它并破译它在做什么。我进行了以下更改:

  • 有意义的变量名
  • 使用prototype
  • require() 使用参数变量
  • alert()默认情况下不返回任何消息
  • 修复了一些语法错误和我遇到的范围问题

再次感谢Erwinus,该功能本身已经存在。

function ScriptLoader() {
}

ScriptLoader.prototype = {

    timer: function (times, // number of times to try
                     delay, // delay per try
                     delayMore, // extra delay per try (additional to delay)
                     test, // called each try, timer stops if this returns true
                     failure, // called on failure
                     result // used internally, shouldn't be passed
            ) {
        var me = this;
        if (times == -1 || times > 0) {
            setTimeout(function () {
                result = (test()) ? 1 : 0;
                me.timer((result) ? 0 : (times > 0) ? --times : times, delay + ((delayMore) ? delayMore : 0), delayMore, test, failure, result);
            }, (result || delay < 0) ? 0.1 : delay);
        } else if (typeof failure == 'function') {
            setTimeout(failure, 1);
        }
    },

    addEvent: function (el, eventName, eventFunc) {
        if (typeof el != 'object') {
            return false;
        }

        if (el.addEventListener) {
            el.addEventListener(eventName, eventFunc, false);
            return true;
        }

        if (el.attachEvent) {
            el.attachEvent("on" + eventName, eventFunc);
            return true;
        }

        return false;
    },

    // add script to dom
    require: function (url, args) {
        var me = this;
        args = args || {};

        var scriptTag = document.createElement('script');
        var headTag = document.getElementsByTagName('head')[0];
        if (!headTag) {
            return false;
        }

        setTimeout(function () {
            var f = (typeof args.success == 'function') ? args.success : function () {
            };
            args.failure = (typeof args.failure == 'function') ? args.failure : function () {
            };
            var fail = function () {
                if (!scriptTag.__es) {
                    scriptTag.__es = true;
                    scriptTag.id = 'failed';
                    args.failure(scriptTag);
                }
            };
            scriptTag.onload = function () {
                scriptTag.id = 'loaded';
                f(scriptTag);
            };
            scriptTag.type = 'text/javascript';
            scriptTag.async = (typeof args.async == 'boolean') ? args.async : false;
            scriptTag.charset = 'utf-8';
            me.__es = false;
            me.addEvent(scriptTag, 'error', fail); // when supported
            // when error event is not supported fall back to timer
            me.timer(15, 1000, 0, function () {
                return (scriptTag.id == 'loaded');
            }, function () {
                if (scriptTag.id != 'loaded') {
                    fail();
                }
            });
            scriptTag.src = url;
            setTimeout(function () {
                try {
                    headTag.appendChild(scriptTag);
                } catch (e) {
                    fail();
                }
            }, 1);
        }, (typeof args.delay == 'number') ? args.delay : 1);
        return true;
    }
};

$(document).ready(function () {
    var loader = new ScriptLoader();
    loader.require('resources/templates.js', {
        async: true, success: function () {
            alert('loaded');
        }, failure: function () {
            alert('NOT loaded');
        }
    });
});

4
我被迫使用jQuery的$ .getScript,因为此功能对于MSIE8中的缓存脚本确实失败了,很不幸
Zathrus Writer

@ZathrusWriter可能是一个更好的主意,感谢您告诉我们!您可能会在此代码中向URL添加一个随机int,它将删除缓存。
Aram Kocharyan 2013年

2
是的Aram,肯定可以解决问题,但是它也会使浏览器的缓存无效,因此在这种情况下的开销可能并不值得;)
Zathrus Writer

@ZathrusWriter,那么jQuery实现的工作原理如何?
Pacerier,2014年

@Pacerier抱歉,我不是jQuery核心开发人员,所以我无法真正回答
Zathrus Writer 2014年

18

我工作的清洁解决方案(2017)

function loaderScript(scriptUrl){
   return new Promise(function (res, rej) {
    let script = document.createElement('script');
    script.src = scriptUrl;
    script.type = 'text/javascript';
    script.onError = rej;
    script.async = true;
    script.onload = res;
    script.addEventListener('error',rej);
    script.addEventListener('load',res);
    document.head.appendChild(script);
 })

}

正如Martin所指出的那样:

const event = loaderScript("myscript.js")
  .then(() => { console.log("loaded"); })
  .catch(() => { console.log("error"); });

要么

try{
 await loaderScript("myscript.js")
 console.log("loaded"); 
}catch{
 console.log("error");
}

1
如下使用它:loaderScript("myscript.js").then(() => { console.log("loaded"); }).catch(() => { console.log("error"); });
Martin Wantke

17

我知道这是一个旧线程,但是我为您提供了一个不错的解决方案(我认为)。它是从我的一类中复制过来的,该类可以处理所有AJAX内容。

当无法加载脚本时,它将设置一个错误处理程序,但是当不支持该错误处理程序时,它将退回到一个计时器,该计时器将检查错误15秒钟。

function jsLoader()
{
    var o = this;

    // simple unstopable repeat timer, when t=-1 means endless, when function f() returns true it can be stopped
    o.timer = function(t, i, d, f, fend, b)
    {
        if( t == -1 || t > 0 )
        {
            setTimeout(function() {
                b=(f()) ? 1 : 0;
                o.timer((b) ? 0 : (t>0) ? --t : t, i+((d) ? d : 0), d, f, fend,b );
            }, (b || i < 0) ? 0.1 : i);
        }
        else if(typeof fend == 'function')
        {
            setTimeout(fend, 1);
        }
    };

    o.addEvent = function(el, eventName, eventFunc)
    {
        if(typeof el != 'object')
        {
            return false;
        }

        if(el.addEventListener)
        {
            el.addEventListener (eventName, eventFunc, false);
            return true;
        }

        if(el.attachEvent)
        {
            el.attachEvent("on" + eventName, eventFunc);
            return true;
        }

        return false;
    };

    // add script to dom
    o.require = function(s, delay, baSync, fCallback, fErr)
    {
        var oo = document.createElement('script'),
        oHead = document.getElementsByTagName('head')[0];
        if(!oHead)
        {
            return false;
        }

        setTimeout( function() {
            var f = (typeof fCallback == 'function') ? fCallback : function(){};
            fErr = (typeof fErr == 'function') ? fErr : function(){
                alert('require: Cannot load resource -'+s);
            },
            fe = function(){
                if(!oo.__es)
                {
                    oo.__es = true;
                    oo.id = 'failed';
                    fErr(oo);
                }
            };
            oo.onload = function() {
                oo.id = 'loaded';
                f(oo);
            };
            oo.type = 'text/javascript';
            oo.async = (typeof baSync == 'boolean') ? baSync : false;
            oo.charset = 'utf-8';
            o.__es = false;
            o.addEvent( oo, 'error', fe ); // when supported

            // when error event is not supported fall back to timer
            o.timer(15, 1000, 0, function() {
                return (oo.id == 'loaded');
            }, function(){ 
                if(oo.id != 'loaded'){
                    fe();
                }
            });
            oo.src = s;
            setTimeout(function() {
                try{
                    oHead.appendChild(oo);
                }catch(e){
                    fe();
                }
            },1); 
        }, (typeof delay == 'number') ? delay : 1);  
        return true;
    };

}

$(document).ready( function()
{
    var ol = new jsLoader();
    ol.require('myscript.js', 800, true, function(){
        alert('loaded');
    }, function() {
        alert('NOT loaded');
    });
});

4
... jQuery是从哪里来的?
Naftali又名Neal,

1
而且,这是一个跨浏览器的解决方案;-)
Codebeat 2011年

1
@Erwinus我没有检查标题,这只是我执行的跨浏览器的快速检查,并且$ .getScript始终运行没有问题,所以我坚持使用它...欢迎您尝试一下,我使用的是W7和XAMPP在这里
Zathrus作家

19
不管它是否奏效,阅读起来都非常痛苦-更不用说调试了。那是相当差的格式和真正糟糕的编码风格。仅变量命名就是一团糟。
Thor84no 2014年

7
如果您看不到可读代码的价值(并且可以在不更改实际执行的代码的情况下使代码具有可读性),那么对于每个必须与您和您的代码一起工作的人,我感到抱歉。
Thor84no 2014年

10

要检查javascript中是否nonexistant.js没有返回错误,您必须在http://fail.org/nonexistant.jslike中添加一个变量var isExecuted = true;,然后在加载script标签时检查它是否存在。

但是,如果您只想检查nonexistant.js返回的结果是否不含404(表示存在),则可以尝试使用isLoaded变量...

var isExecuted = false;
var isLoaded = false;
script_tag.onload = script_tag.onreadystatechange = function() {
    if(!this.readyState ||
        this.readyState == "loaded" || this.readyState == "complete") {
        // script successfully loaded
        isLoaded = true;

        if(isExecuted) // no error
    }
}

这将涵盖两种情况。


1
它可以工作,但并不能真正满足我的要求-在这种情况下,失败永远不会触发事件。我不想轮询变量,如果几秒钟后它仍然为false,则触发失败回调。
大卫,

您尝试检索哪种错误?加载失败?无法在nonexstant.js中执行javascript吗?HTTP响应错误?请更具描述性。
卡·马太斯

以上任何一个都很好。不过,我特别关心404错误。
大卫,

404,这意味着您要检查文件nonexistant.js是否不存在?但是,如果您要检查它是否没有返回错误?
卡·马太斯

嗨,大卫,您应该可以假定,如果this.readyState / ...不正确,则脚本加载失败。基本上是一个onError。
科迪2012年

7

我希望这不会被否决,因为在特殊情况下,这是解决问题的最可靠方法。每当服务器允许您使用CORS(http://en.wikipedia.org/wiki/Cross-origin_resource_sharing)获取Javascript资源时,您都有许多选择。

使用XMLHttpRequest来获取资源将在包括IE在内的所有现代浏览器中运行。由于您要加载Javascript,因此首先要使用Javascript。您可以使用readyState(http://en.wikipedia.org/wiki/XMLHttpRequest#The_onreadystatechange_event_listener)跟踪进度。最后,一旦收到文件的内容,就可以使用eval()执行它。是的,我说过eval,因为从安全角度而言,它与正常加载脚本没有什么不同。实际上,John Resig提出了类似的技术来具有更好的标签(http://ejohn.org/blog/degrading-script-tags/)。

此方法还允许您将加载与评估分开,并在评估发生之前和之后执行函数。当并行加载脚本但一个接一个地评估脚本时,此功能非常有用-当您将标记放置在HTML中时,浏览器可以轻松完成某些工作,但不允许您在运行时使用Javascript添加脚本。

在加载脚本(http://en.wikipedia.org/wiki/XMLHttpRequest#Cross-domain_requests)时,CORS也比JSONP更可取。但是,如果您正在开发自己的第三方窗口小部件以嵌入到其他站点中,则实际上应该从自己的iframe中的域中加载Javascript文件(再次使用AJAX)

简而言之:

  1. 尝试看看是否可以使用AJAX GET加载资源

  2. 成功加载后使用eval

要改善它:

  1. 查看正在发送的缓存控制标头

  2. 如果需要,可以查看是否将内容缓存在localStorage中

  3. 查看Resig的“降级javascript”以获得更清晰的代码

  4. 查看require.js


注意,这种方式要求原始服务器启用CORS,但情况并非总是如此或可控的:
rogerdpack '16

5

尽管我承认这可能不是解决此问题的最佳方法,但这种技巧对我有用。而不是尝试这样做,您应该了解为什么未加载JavaScript。尝试在服务器等中保留脚本的本地副本,或与尝试从中下载脚本的第三方供应商联系。

无论如何,因此这是解决方法:1)将变量初始化为false 2)在javascript加载时将其设置为true(使用onload属性)3)一旦加载了HTML正文,请检查该变量为true还是false

<html>
  <head>
    <script>
      var scriptLoaded = false;

      function checkScriptLoaded() {
        if (scriptLoaded) {
          // do something here
        } else {
          // do something else here!
        }
      }
    </script>
    <script src="http://some-external-script.js" onload="scriptLoaded=true;" />
  </head>
  <body onload="checkScriptLoaded()">
    <p>My Test Page!</p>
  </body>
</html>

1
如果脚本仍在加载该怎么办?您如何知道未找到文件还是只需要等待?
osa

只要将脚本标记直接放在文档源中,该解决方案就可以在我的测试中使用。在页面源中引用的所有资源都已加载(或失败)之前,文档的onload事件不会触发。但是,如果以后需要将脚本插入DOM,则需要另一种方法。
Jamey Sharp 2013年

很好的解决方案。我不明白为什么它没有得到支持。
Lotfi

假定脚本将被同步加载,阻止其他所有内容,但并非总是如此。实际上,这不是推荐的脚本加载方式。
Vitim.us

4

这是另一个没有计时器的基于JQuery的解决方案:

<script type="text/javascript">
function loadScript(url, onsuccess, onerror) {
$.get(url)
    .done(function() {
        // File/url exists
        console.log("JS Loader: file exists, executing $.getScript "+url)
        $.getScript(url, function() {
            if (onsuccess) {
                console.log("JS Loader: Ok, loaded. Calling onsuccess() for " + url);
                onsuccess();
                console.log("JS Loader: done with onsuccess() for " + url);
            } else {
                console.log("JS Loader: Ok, loaded, no onsuccess() callback " + url)
            }
        });
    }).fail(function() {
            // File/url does not exist
            if (onerror) {
                console.error("JS Loader: probably 404 not found. Not calling $.getScript. Calling onerror() for " + url);
                onerror();
                console.error("JS Loader: done with onerror() for " + url);
            } else {
                console.error("JS Loader: probably 404 not found. Not calling $.getScript. No onerror() callback " + url);
            }
    });
}
</script>

感谢:https : //stackoverflow.com/a/14691735/1243926

用法示例(来自JQuery getScript文档的原始示例):

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>jQuery.getScript demo</title>
  <style>
  .block {
     background-color: blue;
     width: 150px;
     height: 70px;
     margin: 10px;
  }
  </style>
  <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
</head>
<body>

<button id="go">&raquo; Run</button>
<div class="block"></div>

<script>


function loadScript(url, onsuccess, onerror) {
$.get(url)
    .done(function() {
        // File/url exists
        console.log("JS Loader: file exists, executing $.getScript "+url)
        $.getScript(url, function() {
            if (onsuccess) {
                console.log("JS Loader: Ok, loaded. Calling onsuccess() for " + url);
                onsuccess();
                console.log("JS Loader: done with onsuccess() for " + url);
            } else {
                console.log("JS Loader: Ok, loaded, no onsuccess() callback " + url)
            }
        });
    }).fail(function() {
            // File/url does not exist
            if (onerror) {
                console.error("JS Loader: probably 404 not found. Not calling $.getScript. Calling onerror() for " + url);
                onerror();
                console.error("JS Loader: done with onerror() for " + url);
            } else {
                console.error("JS Loader: probably 404 not found. Not calling $.getScript. No onerror() callback " + url);
            }
    });
}


loadScript("https://raw.github.com/jquery/jquery-color/master/jquery.color.js", function() {
  console.log("loaded jquery-color");
  $( "#go" ).click(function() {
    $( ".block" )
      .animate({
        backgroundColor: "rgb(255, 180, 180)"
      }, 1000 )
      .delay( 500 )
      .animate({
        backgroundColor: "olive"
      }, 1000 )
      .delay( 500 )
      .animate({
        backgroundColor: "#00f"
      }, 1000 );
  });
}, function() { console.error("Cannot load jquery-color"); });


</script>
</body>
</html>

好谢尔盖!因此,您正在使用.get()检查文件是否存在,并使用.getScript()检查文件是否可以正确执行/加载?
jjwdesign 2013年

2
是。我记得这种方法确实有局限性:如果我没记错的话,由于跨域脚本的限制,您将无法以这种方式加载许多脚本。
osa

使用jQuery(或另一个库)的问题是您需要首先加载该库。那么,如何检查库是否加载失败?
Pacerier,2014年

我也采用了这种方法,但是我建议将其cache:true用于$ .getScript调用(默认情况下处于关闭状态)。这样,对于大多数请求,它会自动将缓存版本用于getScript调用(节省您的延迟)
Laurens Rietveld

2

使用诺言可以安全地完成此操作

function loadScript(src) {
  return new Promise(function(resolve, reject) {
    let script = document.createElement('script');
    script.src = src;

    script.onload = () => resolve(script);
    script.onerror = () => reject(new Error("Script load error: " + src));

    document.head.append(script);
  });
}

像这样使用

let promise = loadScript("https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js");

promise.then(
  script => alert(`${script.src} is loaded!`),
  error => alert(`Error: ${error.message}`)
);

1

它在Safari中不起作用的原因是因为您使用的是属性语法。但这可以正常工作:

script_tag.addEventListener('error', function(){/*...*/}, true);

...除了IE中。

如果要检查脚本是否成功执行,只需使用该脚本设置变量并检查是否在外部代码中设置了该变量。


对于Safari而言,这实际上没有任何区别-它仍然不会触发错误处理程序。
大卫,

我在野生动物园中使用onclick处理程序时遇到了问题,而这正是解决该问题的方法,因此我认为onerror也是如此。显然不是...

1
这是否也适用于静态包含的脚本标记,或者仅适用于动态注入的脚本标记?我只是试图用它来检测jQuery是否无法加载,但是没有用。我不确定自己做错了还是在这种情况下不起作用。
hippietrail 2011年

1
@hippietrail-事件侦听器永远无法在静态HTML上运行<script>。如果您尝试在之前添加它,则会收到错误消息,指出该标记不存在;如果在此之后添加,则脚本已经运行并触发了其事件。唯一的方法是查找由脚本引起的副作用。

谢谢麻烦。不幸的是,这仅适用于404,不适用于JS错误。在脚本内设置变量并不总是可行的。
Jo Liss 2012年

0

建议设置一个超时,然后在超时后承担负载故障。

setTimeout(fireCustomOnerror, 4000);

这种方法的问题在于假设是基于偶然性的。超时到期后,请求仍待处理。即使程序员认为不会发生加载,对待处理脚本的请求也可能加载。

如果可以取消请求,则程序可以等待一段时间,然后取消请求。


0

这就是我使用promise检测窗口对象上发出的加载错误的方式:

<script type='module'>
window.addEventListener('error', function(error) {
  let url = error.filename
  url = url.substring(0, (url.indexOf("#") == -1) ? url.length : url.indexOf("#"));
  url = url.substring(0, (url.indexOf("?") == -1) ? url.length : url.indexOf("?"));
  url = url.substring(url.lastIndexOf("/") + 1, url.length);
  window.scriptLoadReject && window.scriptLoadReject[url] && window.scriptLoadReject[url](error);
}, true);
window.boot=function boot() {
  const t=document.createElement('script');
  t.id='index.mjs';
  t.type='module';
  new Promise((resolve, reject) => {
    window.scriptLoadReject = window.scriptLoadReject || {};
    window.scriptLoadReject[t.id] = reject;
    t.addEventListener('error', reject);
    t.addEventListener('load', resolve); // Careful load is sometimes called even if errors prevent your script from running! This promise is only meant to catch errors while loading the file.
  }).catch((value) => {
    document.body.innerHTML='Error loading ' + t.id + '! Please reload this webpage.<br/>If this error persists, please try again later.<div><br/>' + t.id + ':' + value.lineno + ':' + value.colno + '<br/>' + (value && value.message);
  });
  t.src='./index.mjs'+'?'+new Date().getTime();
  document.head.appendChild(t);
};
</script>
<script nomodule>document.body.innerHTML='This website needs ES6 Modules!<br/>Please enable ES6 Modules and then reload this webpage.';</script>
</head>

<body onload="boot()" style="margin: 0;border: 0;padding: 0;text-align: center;">
  <noscript>This website needs JavaScript!<br/>Please enable JavaScript and then reload this webpage.</noscript>

0

好吧,我想做自己想做的所有事情的唯一方法就是丑陋。首先执行AJAX调用以检索Javascript文件内容。完成此操作后,您可以检查状态代码来确定是否成功。然后从xhr对象获取responseText并将其包装在try / catch中,动态创建脚本标签,对于IE,您可以将脚本标签的text属性设置为JS文本,在所有其他浏览器中,您应该能够将带有内容的文本节点追加到script标签。如果有任何代码期望script标记实际包含文件的src位置,则此操作将无效,但在大多数情况下应该没问题。


该解决方案在现代浏览器中已过时。
Simon_Weaver

0

错误事件

* 2017年8月更新:Chrome和Firefox会触发onerror。Internet Explorer会触发onload。Edge不会触发onerror或onload。我不会使用此方法,但在某些情况下可以使用。也可以看看

<link> onerror在IE中不起作用

*

定义和用法 如果在加载外部文件(例如文档或图像)时发生错误,则会触发onerror事件。

提示:在音频/视频媒体上使用时,在对媒体加载过程造成某种干扰时发生的相关事件是:

  • Onabort
  • 空着的
  • 已安装
  • 暂停

在HTML中:

元素onerror =“ myScript”>

在JavaScript中,使用addEventListener()方法:

object.addEventListener(“ error”,myScript);

注意: Internet Explorer 8和更早版本不支持addEventListener()方法。

示例 如果加载图像时发生错误,请执行JavaScript:

img src =“ image.gif” onerror =“ myFunction()”>

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.