jquery 我可以使用`fetch`从另一个脚本运行JS脚本吗?

11dmarpk  于 2023-06-22  发布在  jQuery
关注(0)|答案(6)|浏览(114)

初级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”。你是指别的吗

hwamh0ep

hwamh0ep1#

Fetch API应该提供基于Promise的API来获取远程数据。加载随机远程脚本不是 AJAX --即使jQuery.ajax能够做到这一点。它不会被Fetch API处理。
脚本可以动态追加并使用promise Package :

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(() => { ... });
nhjlsmyf

nhjlsmyf2#

这里有几件事要提一下。
是的,可以执行刚从服务器加载的JavaScript。您可以以文本和用户eval(...)的形式获取文件,但由于无法跟踪的副作用和缺乏安全性,不建议这样做!
另一种选择是:1.加载JavaScript文件2.用文件内容(或URL,因为浏览器缓存文件)创建一个脚本标记
这是可行的,但它可能无法从回调地狱中解放出来。
如果你想要的是加载其他你可以使用的JavaScript文件,例如requirejs,你可以定义模块并加载它们。查看http://requirejs.org/
如果你真的想摆脱回调地狱,你需要做的是

  • 定义函数(您可以将它们放在同一个文件中,或者在客户端使用requirejs从另一个文件加载,或者如果您可以在部署之前进行编译,则使用webpack)
  • 如果需要的话,使用promise或streams(参见Rxjs https://github.com/Reactive-Extensions/RxJS
  • 记住那个promise.然后返回一个promise
someAsyncThing()
  .then(doSomethingAndResolveAnotherAsncThing)
  .then(doSomethingAsyncAgain)

记住Promise是可以组合的

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

bjp0bcyl3#

是的你可以

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

不要听选择的“正确”答案。

wj8zmpe1

wj8zmpe14#

遵循fetch() API对我来说非常好,正如@cnexans的回答所建议的那样(使用.text(),然后使用.eval())。我注意到与添加<script>标记的方法相比,性能有所提高

运行代码片段查看fetch() API加载async(因为是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>
ovfsdjhp

ovfsdjhp5#

Fetch API提供了用于获取资源(包括通过网络)的接口。对于使用过XMLHttpRequest的人来说,它似乎很熟悉,但新的API提供了更强大、更灵活的特性集。https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
这就是它应该做的,但不幸的是,它不评估脚本。
这就是为什么我在Github上发布了这个小小的Fetch data loader
它将获取的内容加载到目标容器中并运行其脚本(不使用邪恶的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>
fsi0uk1n

fsi0uk1n6#

要实际使用动态加载的.js文件中的变量,需要等待文件加载完成。下面的方法将fetch Package 在Promise中,以便轻松调用async/await
script标记添加为blob还简化了使用script-src-elem 'self' blob:;而不是nonce的CSP配置。整个解决方案比使用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>

相关问题