'Can I run a JS script from another using `fetch`?
Lower intermediate JS/JQ person here.
I'm trying to escape callback hell by using JS fetch. This is billed as "the replacement for AJAX" and seems to be pretty powerful. I can see how you can get HTML and JSON objects with it... but is it capable of running another JS script from the one you're in? Maybe there's another new function in ES6 to do:
$.getScript( 'xxx.js' );
i.e.
$.ajax({ url : 'xxx.js', dataType : "script", });
...?
later, response to Joseph The Dreamer:
Tried this:
const createdScript = $(document.createElement('script')).attr('src', 'generic.js');
fetch( createdScript )...
... it didn't run the script "generic.js". Did you mean something else?
Solution 1:[1]
There are a few things to mention on here.
Yes, it is possible to execute a javascript just loaded from the server. You can fetch the file as text and user eval(...) while this is not recommended because of untrackeable side effects and lack of security!
Another option would be: 1. Load the javascript file 2. Create a script tag with the file contents (or url, since the browser caches the file)
This works, but it may not free you from callback hell perse.
If what you want is load other javascript files dinamically you can use, for example requirejs, you can define modules and load them dinamically. Take a look at http://requirejs.org/
If you really want to get out of the callback hell, what you need to do is
- Define functions (you can have them in the same file or load from another file using requirejs in the client, or webpack if you can afford a compilation before deployment)
- Use promises or streams if needed (see Rxjs https://github.com/Reactive-Extensions/RxJS)
Remember that promise.then returns a promise
someAsyncThing() .then(doSomethingAndResolveAnotherAsncThing) .then(doSomethingAsyncAgain)
Remember that promises can be composed
Promise.all(somePromise, anotherPromise, fetchFromServer)
.then(doSomethingWhenAllOfThoseAreResolved)
Solution 2:[2]
Following fetch() Api works perfectly well for me, as proposed by answer of @cnexans (using .text() and then .eval()). I noticed an increased performance compared to method of adding the <script> tag.
Run code snippet to see the fetch() API loading async (as it is a Promise):
// Loading moment.min.js as sample script
// only use eval() for sites you trust
fetch('https://momentjs.com/downloads/moment.min.js')
.then(response => response.text())
.then(txt => eval(txt))
.then(() => {
document.getElementById('status').innerHTML = 'moment.min.js loaded'
// now you can use the script
document.getElementById('today').innerHTML = moment().format('dddd');
document.getElementById('today').style.color = 'green';
})
#today {
color: orange;
}
<div id='status'>loading 'moment.min.js' ...</div>
<br>
<div id='today'>please wait ...</div>
Solution 3:[3]
yes u can
<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>
dont listen to the selected "right" answer.
Solution 4:[4]
The Fetch API provides an interface for fetching resources (including across the network). It will seem familiar to anyone who has used XMLHttpRequest, but the new API provides a more powerful and flexible feature set. https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
That's what it's supposed to do, but unfortunately it doesn't evaluate the script.
That's why I released this tiny Fetch data loader on Github.
It loads the fetched content into a target container and run its scripts (without using the evil eval() function.
A demo is available here: https://www.ajax-fetch-data-loader.miglisoft.com
Here's a sample code:
<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>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | cnexans |
| Solution 2 | |
| Solution 3 | Bob Stein |
| Solution 4 | migli |
