Асинхронный Script Загрузка обратного вызова
http://jsfiddle.net/JamesKyle/HQDu6/
Я создал короткую функцию, основанную на Матиас Биненс Оптимизация асинхронного script Google Analytics, которая выглядит следующим образом:
function async(src) {
var d = document, t = 'script',
o = d.createElement(t),
s = d.getElementsByTagName(t)[0];
o.src = '//' + src;
s.parentNode.insertBefore(o, s);
}
Это отлично работает, и я уже начал использовать его для нескольких сценариев
// Crazy Egg
async('dnn506yrbagrg.cloudfront.net/pages/scripts/XXXXX/XXXXX.js?' + Math.floor(new Date().getTime() / 3600000));
// User Voice
var uvOptions = {};
async('widget.uservoice.com/XXXXX.js');
// Google Analytics
var _gaq = [['_setAccount', 'UA-XXXXX-XX'], ['_setDomainName', 'coachup.com'], ['_trackPageview']];
async('google-analytics.com/ga.js');
// Stripe
async('js.stripe.com/v1');
Проблема возникает, когда я сталкиваюсь с script, который нужно вызвать после загрузки:
// Snap Engage
async('snapabug.appspot.com/snapabug.js');
SnapABug.init('XXXXX-XXXXX-XXXXX-XXXXX-XXXXX');
Итак, я решил, что превращу это в функцию обратного вызова, которая будет использоваться так:
async('snapabug.appspot.com/snapabug.js', function() {
SnapABug.init('XXXXX-XXXXX-XXXXX-XXXXX-XXXXX');
});
Я не ожидал, что это будет трудно для меня сделать, но так получилось.
Мой вопрос - это самый эффективный способ добавить обратный вызов без чрезмерного нарушения кода.
См. jsfiddle: http://jsfiddle.net/JamesKyle/HQDu6/
Ответы
Ответ 1
Спасибо RASG за fooobar.com/questions/138721/...
Функция Async с обратным вызовом:
function async(u, c) {
var d = document, t = 'script',
o = d.createElement(t),
s = d.getElementsByTagName(t)[0];
o.src = '//' + u;
if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
s.parentNode.insertBefore(o, s);
}
Использование:
async('snapabug.appspot.com/snapabug.js', function() {
SnapABug.init('XXXXX-XXXXX-XXXXX-XXXXX-XXXXX');
});
jsFiddle
Ответ 2
Более свежий фрагмент:
async function loadAsync(src) {
const script = document.createElement('script');
script.src = src;
return new Promise((resolve, reject) => {
script.onreadystatechange = function () {
if (script.readyState === 'loaded' || script.readyState === 'complete') {
script.onreadystatechange = null;
resolve(true);
}
};
document.getElementsByTagName('head')[0].appendChild(script);
});
}
использование
loadAsync('https://....js').then(_ => {
// ... script loaded here
})
Ответ Джеймса Кайла не учитывает IE9. Вот модифицированная версия кода, которую я нашел по ссылке, предложенной в комментариях. Измените var baseUrl, чтобы он мог соответствующим образом найти скрипт.
//for requiring a script loaded asynchronously.
function loadAsync(src, callback, relative){
var baseUrl = "/resources/script/";
var script = document.createElement('script');
if(relative === true){
script.src = baseUrl + src;
}else{
script.src = src;
}
if(callback !== null){
if (script.readyState) { // IE, incl. IE9
script.onreadystatechange = function() {
if (script.readyState === "loaded" || script.readyState === "complete") {
script.onreadystatechange = null;
callback();
}
};
} else {
script.onload = function() { // Other browsers
callback();
};
}
}
document.getElementsByTagName('head')[0].appendChild(script);
}
использование:
loadAsync('https://www.gstatic.com/charts/loader.js' , function(){
chart.loadCharts();
});
// OR relative path
loadAsync('fastclick.js', null, true);
Ответ 3
Другие ответы работают хорошо, но не являются супер читаемыми или требуют обещаний. Вот мои два цента:
function loadScript(src, callback) {
var script = document.createElement('script');
script.setAttribute('src', src);
script.addEventListener('load', callback);
document.head.appendChild(script);
},