簡體   English   中英

我可以使用“fetch”從另一個運行 JS 腳本嗎?

[英]Can I run a JS script from another using `fetch`?

低中級 JS/JQ 人在這里。

我試圖通過使用 JS fetch來逃避回調地獄。 這被稱為“AJAX 的替代品”並且似乎非常強大。 我可以看到您如何使用它獲得 HTML 和 JSON 對象...但是它是否能夠從您所在的腳本運行另一個 JS 腳本? 也許 ES6 中還有另一個新的 function 可以做:

$.getScript( 'xxx.js' );

IE

$.ajax({ url : 'xxx.js', dataType : "script", });

……?

后來,對夢想家約瑟夫的回應:

試過這個:

const createdScript = $(document.createElement('script')).attr('src', 'generic.js');
fetch( createdScript )...

...它沒有運行腳本“generic.js”。 你是不是另有意思?

Fetch API應該提供基於promise的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應該為腳本加載提供基於promise的API,也可以使用:

System.config({
  meta: {
    '*': { format: 'global' }
  }
});

System.import('foo.js').then(() => { ... });

這里有幾點需要注意。


是的,可以執行剛從服務器加載的javascript。 您可以將文件作為文本和用戶eval(...)獲取,但不推薦這樣做,因為副作用難以置信且缺乏安全性!

另一種選擇是:1。加載javascript文件2.使用文件內容(或url,因為瀏覽器緩存文件)創建腳本標記

這有效,但它可能無法讓你從回調地獄中解脫出來。


如果您想要的是加載其他javascript文件,您可以使用,例如requirejs,您可以定義模塊並以dinamically方式加載它們。 看看http://requirejs.org/


如果你真的想擺脫回調地獄,你需要做的是

  • 定義函數(您可以將它們放在同一個文件中,或者使用客戶端中的requirejs從另一個文件加載,如果在部署之前可以負擔編譯,則可以使用webpack)
  • 如果需要,請使用promises或streams(請參閱Rxjs https://github.com/Reactive-Extensions/RxJS
  • 記住,promise.then返回一個承諾

     someAsyncThing() .then(doSomethingAndResolveAnotherAsncThing) .then(doSomethingAsyncAgain) 

請記住,承諾可以組成

Promise.all(somePromise, anotherPromise, fetchFromServer)
  .then(doSomethingWhenAllOfThoseAreResolved)

是的你可以<\/strong>

<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>

正如@cnexans 的回答所建議的那樣,遵循fetch() Api 對我來說效果很好(使用.text()然后.eval() )。 我注意到與添加<script>標記的方法相比性能有所提高

運行代碼片段以查看fetch() API異步加載(因為它是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>

Fetch API 提供了一個用於獲取資源(包括跨網絡)的接口。 任何使用過 XMLHttpRequest 的人都會覺得它很熟悉,但新的 API 提供了更強大、更靈活的功能集。 https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API

這就是它應該做的,但不幸的是它不會評估腳本。

這就是我在 Github 上發布這個小型Fetch 數據加載器的原因。

它將獲取的內容加載到目標容器中並運行其腳本(不使用邪惡的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>

要實際使用動態加載的 .js 文件中的變量,必須等待文件完成加載。 以下方法將提取fetchPromise中,以便於async/await調用。

script標記添加為blob還可以使用script-src-elem 'self' blob:; 而不是隨機數。 整個解決方案比使用eval()更安全。

 const ns = { //injects client js file require: async u => { await new Promise((res, rej) => { fetch(u).then(r => r.ok? r.blob(): rej).then(b => { let ou = URL.createObjectURL(b), el = document.createElement("script"); el.setAttribute("src", ou); el.setAttribute("type", "text/javascript"); el.onload = () => res(); document.body.appendChild(el); }).catch(e => rej); }); }, } await ns.require('/path/to/dynamically_loaded.js'); console.log(var_declared_inside_loaded_file);
 <html lang="en"> <head> <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" /> <meta http-equiv="Content-Security-Policy" content=" default-src 'self'; script-src-elem 'self' blob:; " /> </head>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM