Могу ли я запустить JS-скрипт из другого, используя `fetch`?
Ниже среднего JS/JQ человек здесь.
Я пытаюсь избежать ада обратного вызова с помощью JS fetch
, Это объявлено как "замена AJAX" и кажется довольно мощным. Я могу видеть, как вы можете получить объекты HTML и JSON с ним... но способен ли он запустить другой сценарий JS из того, в котором вы находитесь? Возможно, в ES6 есть еще одна новая функция:
$.getScript( 'xxx.js' );
т.е.
$.ajax({ url : 'xxx.js', dataType : "script", });
...?
позже ответ Джозефу Мечтателю:
Пробовал это:
const createdScript = $(document.createElement('script')).attr('src', 'generic.js');
fetch( createdScript )...
... он не запускал скрипт "generic.js". Вы имели в виду что-то еще?
6 ответов
Предполагается, что Fetch API предоставляет API на основе обещаний для извлечения удаленных данных. Загрузка случайного удаленного скрипта не AJAX - даже если jQuery.ajax
способен на это. Это не будет обработано Fetch API.
Сценарий может быть добавлен динамически и заключен в обещание:
const scriptPromise = new Promise((resolve, reject) => {
const script = document.createElement('script');
document.body.appendChild(script);
script.onload = resolve;
script.onerror = reject;
script.async = true;
script.src = 'foo.js';
});
scriptPromise.then(() => { ... });
SystemJS должен предоставлять API на основе обещаний для загрузки скриптов и может также использоваться:
System.config({
meta: {
'*': { format: 'global' }
}
});
System.import('foo.js').then(() => { ... });
да ты можешь
<script>
fetch('https://evil.com/1.txt') .then(function(response) { if (!response.ok) { return false; } return response.blob(); }) .then(function(myBlob) { var objectURL = URL.createObjectURL(myBlob); var sc = document.createElement("script"); sc.setAttribute("src", objectURL); sc.setAttribute("type", "text/javascript"); document.head.appendChild(sc);})
</script>
не слушайте выбранный «правильный» ответ.
Есть несколько вещей, чтобы упомянуть здесь.
Да, можно выполнить только что загруженный с сервера javascript. Вы можете получить файл как текстовый и пользовательский eval(...), хотя это не рекомендуется из-за неотслеживаемых побочных эффектов и отсутствия безопасности!
Другой вариант: 1. Загрузите файл javascript. 2. Создайте тег сценария с содержимым файла (или URL, поскольку браузер кэширует файл).
Это работает, но может не освободить вас от адского обратного вызова.
Если вам нужно динамически загружать другие файлы javascript, которые вы можете использовать, например requirejs, вы можете определять модули и загружать их динамически. Взгляните на http://requirejs.org/
Если вы действительно хотите выбраться из ада обратного вызова, вам нужно сделать следующее:
- Определите функции (вы можете поместить их в один и тот же файл или загрузить из другого файла, используя requirejs на клиенте, или веб-пакет, если вы можете позволить компиляцию перед развертыванием)
- При необходимости используйте обещания или потоки (см. Rxjs https://github.com/Reactive-Extensions/RxJS).
Помните, что обещание. Затем возвращает обещание
someAsyncThing() .then(doSomethingAndResolveAnotherAsncThing) .then(doSomethingAsyncAgain)
Помните, что обещания могут быть составлены
Promise.all(somePromise, anotherPromise, fetchFromServer)
.then(doSomethingWhenAllOfThoseAreResolved)
Для меня отлично работает Api.
Запустите фрагмент кода, чтобы увидеть
fetch()
API загрузка асинхронный (как это обещание ):
Чтобы фактически использовать переменную из динамически загружаемого файла .js, необходимо дождаться завершения загрузки файла. Следующий подход оборачиваетfetch
вPromise
для легкогоasync/await
звонки.
Добавлениеscript
пометить какblob
также упрощает настройку CSP с помощьюscript-src-elem 'self' blob:;
вместо одноразовых номеров. Все решение безопаснее, чем использованиеeval()
.
Fetch API предоставляет интерфейс для получения ресурсов (в том числе по сети). Он покажется знакомым любому, кто использовал XMLHttpRequest, но новый API предоставляет более мощный и гибкий набор функций. https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
Это то, что он должен делать, но, к сожалению, он не оценивает сценарий.
Вот почему я выпустил этот крошечный загрузчик данных Fetch на Github.
Он загружает извлеченный контент в целевой контейнер и запускает его скрипты (без использования злого
eval()
функция.
Демо доступно здесь: https://www.ajax-fetch-data-loader.miglisoft.com
Вот пример кода:
<script>
document.addEventListener('DOMContentLoaded', function(event) {
fetch('ajax-content.php')
.then(function (response) {
return response.text()
})
.then(function (html) {
console.info('content has been fetched from data.html');
loadData(html, '#ajax-target').then(function (html) {
console.info('I\'m a callback');
})
}).catch((error) => {
console.log(error);
});
});
</script>