Javascript Require.js 和在 DOM 中简单地创建一个 <script> 元素有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4915201/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the difference between Require.js and simply creating a <script> element in the DOM?
提问by maxedison
What's the difference between using Require.JS amd simply creating a <script>
element in the DOM?
使用 Require.JS 和简单地<script>
在 DOM 中创建一个元素有什么区别?
My understanding of Require.JS is that it offers the ability to load dependencies, but can this not simply be done by creating a <script>
element that loads the necessary external JS file?
我对 Require.JS 的理解是它提供了加载依赖的能力,但是这不是简单地通过创建一个<script>
加载必要的外部 JS 文件的元素来完成吗?
For example, lets assume I have the function doStuff()
, which requires the function needMe()
. doStuff()
is in the external file do_stuff.js
, while needMe()
is in the external file need_me.js
.
例如,假设我有函数doStuff()
,它需要函数needMe()
。doStuff()
在外部文件中do_stuff.js
,而needMe()
在外部文件中need_me.js
。
Doing this the Require.JS way:
以 Require.JS 方式执行此操作:
define(['need_me'],function(){
function doStuff(){
//do some stuff
needMe();
//do some more stuff
}
});
Doing this by simply creating a script element:
通过简单地创建一个脚本元素来做到这一点:
function doStuff(){
var scriptElement = document.createElement('script');
scriptElement.src = 'need_me.js';
scriptElement.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(scriptElement);
//do some stuff
needMe();
//do some more stuff
}
Both of these work. However, the second version doesn't require me to load all of the Require.js library. I don't really see any functional difference...
这两个都有效。但是,第二个版本不需要我加载所有的 Require.js 库。我真的没有看到任何功能差异......
采纳答案by Sarfraz
Here is the nice article on ajaxian.com as to why use it:
这是 ajaxian.com 上关于为什么使用它的好文章:
RequireJS: Asynchronous JavaScript loading
- some sort of #include/import/require
- ability to load nested dependencies
- ease of use for developer but then backed by an optimization tool that helps deployment
- 某种#include/import/require
- 加载嵌套依赖项的能力
- 易于开发人员使用,但随后由有助于部署的优化工具提供支持
回答by jmort253
What advantages does Require.JS offer in comparison to simply creating a element in the DOM?
与简单地在 DOM 中创建元素相比,Require.JS 有哪些优势?
In your example, you're creating the script tag asynchronously, which means your needMe()
function would be invoked beforethe need_me.js file finishes loading. This results in uncaught exceptions where your function is not defined.
在您的示例中,您正在异步创建脚本标记,这意味着您的needMe()
函数将在 need_me.js 文件完成加载之前被调用。这会导致未定义函数的未捕获异常。
Instead, to make what you're suggesting actually work, you'd need to do something like this:
相反,要使您的建议真正起作用,您需要执行以下操作:
function doStuff(){
var scriptElement = document.createElement('script');
scriptElement.src = 'need_me.js';
scriptElement.type = 'text/javascript';
scriptElement.addEventListener("load",
function() {
console.log("script loaded - now it's safe to use it!");
// do some stuff
needMe();
//do some more stuff
}, false);
document.getElementsByTagName('head')[0].appendChild(scriptElement);
}
Arguably, it may or may not be best to use a package manager such as RequireJS or to utilize a pure-JavaScript strategy as demonstrated above. While your Web application may load faster, invoking functionality and features on the site would be slower since it would involve waiting for resources to load before that action could be performed.
可以说,使用 RequireJS 之类的包管理器或使用纯 JavaScript 策略可能是最好的,也可能不是。虽然您的 Web 应用程序可能加载得更快,但调用站点上的功能和特性会更慢,因为它需要在执行该操作之前等待资源加载。
If a Web application is built as a single-page app, then consider that people won't actually be reloading the page very often. In these cases, preloading everything would help make the experience seem faster when actually usingthe app. In these cases, you're right, one can merely load all resources simply by including the script tags in the head or body of the page.
如果将 Web 应用程序构建为单页应用程序,请考虑人们实际上不会经常重新加载页面。在这些情况下,预加载所有内容将有助于使实际使用应用程序时的体验看起来更快。在这些情况下,您是对的,只需在页面的头部或正文中包含脚本标记即可加载所有资源。
However, if building a website or a Web application that follows the more traditional model where one transitions from page to page, causing resources to be reloaded, a lazy-loading approach may help speed up these transitions.
但是,如果构建网站或 Web 应用程序遵循更传统的模型,即在页面之间转换,导致资源重新加载,则延迟加载方法可能有助于加速这些转换。
回答by girls_can_code_too
Some other very pointed reasons why using RequireJS makes sense:
使用 RequireJS 有意义的其他一些非常尖锐的原因:
- Managing your own dependencies rapidly falls apart for sizable projects.
- You can have as many small files as you want, and don't have to worry about keeping track of dependencies or load order.
- RequireJS makes it possible to write an entire, modular app without touching window object.
- 对于大型项目,管理自己的依赖项很快就会崩溃。
- 您可以拥有任意数量的小文件,而不必担心跟踪依赖项或加载顺序。
- RequireJS 可以在不接触窗口对象的情况下编写完整的模块化应用程序。
Taken from rmurphey's comments here in this Gist.
Layers of abstraction can be a nightmare to learn and adjust to, but when it serves a purpose and does it well, it just makes sense.
抽象层可能是学习和适应的噩梦,但是当它服务于一个目的并且做得很好时,它就有意义了。
回答by gman
Here's a more concrete example.
这是一个更具体的例子。
I'm working in a project with 60 files. We have 2 different modes of running it.
我正在一个有 60 个文件的项目中工作。我们有 2 种不同的运行模式。
Load a concatenated version, 1 large file. (Production)
Load all 60 files (development)
加载一个连接版本,1 个大文件。(生产)
加载所有 60 个文件(开发)
We're using a loader so we just have one script in the webpage
我们正在使用加载程序,因此网页中只有一个脚本
<script src="loader.js"></script>
That defaults to mode#1 (loading the one large concatenated file). To run the in mode#2 (separate files) we set some flag. It could be anything. A key in the query string. In this example we just do this
默认为模式#1(加载一个大的连接文件)。为了运行模式#2(单独的文件),我们设置了一些标志。它可以是任何东西。查询字符串中的键。在这个例子中,我们只是这样做
<script>useDebugVersion = true;</script>
<script src="loader.js"></script>
loader.js looks something like this
loader.js 看起来像这样
if (useDebugVersion) {
injectScript("app.js");
injectScript("somelib.js");
injectScript("someotherlib.js");
injectScript("anotherlib.js");
... repeat for 60 files ...
} else {
injectScript("large-concatinated.js");
}
The build script is just an .sh file that looks like this
构建脚本只是一个看起来像这样的 .sh 文件
cat > large-concantinated.js app.js somelib.js someotherlib.js anotherlib.js
etc...
等等...
If a new file is added we'll likely be using mode#2 since we're doing development we have to add an injectScript("somenewfile.js")
line to loader.js
如果添加了一个新文件,我们可能会使用 mode#2,因为我们正在进行开发,我们必须injectScript("somenewfile.js")
在 loader.js 中添加一行
Then later for production we also have to add somenewfile.js to our build script. A step we often forget and then get error messages.
然后为了生产,我们还必须将 somenewfile.js 添加到我们的构建脚本中。我们经常忘记的一个步骤,然后收到错误消息。
By switching to AMD we don't have to edit 2 files. The problem of keeping loader.js and the build script in sync goes away. Using r.js
or webpack
it can just read the code to build large-concantinated.js
通过切换到 AMD,我们不必编辑 2 个文件。保持 loader.js 和构建脚本同步的问题消失了。使用r.js
或者webpack
它可以只读取代码来构建large-concantinated.js
It can also deal with dependencies, for example we had 2 files lib1.js and lib2.js loaded like this
它还可以处理依赖关系,例如我们像这样加载了 2 个文件 lib1.js 和 lib2.js
injectScript("lib1.js");
injectScript("lib2.js");
lib2 needs lib1. It has code inside that does something like
lib2 需要 lib1。它里面有代码可以做类似的事情
lib1Api.installPlugin(...);
But as the injected scripts are loaded asynchronously there's no guarantee they'll load in the correct order. These 2 scripts are not AMD scripts but using require.js we can tell it their dependencies
但是由于注入的脚本是异步加载的,因此无法保证它们会以正确的顺序加载。这两个脚本不是 AMD 脚本,但使用 require.js 我们可以告诉它它们的依赖关系
require.config({
paths: {
lib1: './path/to/lib1',
lib2: './path/to/lib2',
},
shim: {
lib1: {
"exports": 'lib1Api',
},
lib2: {
"deps": ["lib1"],
},
}
});
I our module that uses lib1 we do this
我是我们使用 lib1 的模块,我们这样做
define(['lib1'], function(lib1Api) {
lib1Api.doSomething(...);
});
Now require.js will inject the scripts for us and it won't inject lib2 until lib1 has be loaded since we told it lib2 depends on lib1. It also won't start our module that use lib1 until both lib2 and lib1 have loaded.
现在 require.js 将为我们注入脚本,并且在加载 lib1 之前它不会注入 lib2,因为我们告诉它 lib2 依赖于 lib1。它也不会启动我们使用 lib1 的模块,直到 lib2 和 lib1 都已加载。
This makes development nice (no build step, no worrying about loading order) and it makes production nice (no need to update a build script for each script added).
这使开发变得很好(没有构建步骤,不用担心加载顺序)并且它使生产很好(不需要为添加的每个脚本更新构建脚本)。
As an added bonus we can use webpack's babel plugin to run babel over the code for older browsers and again we don't have to maintain that build script either.
作为一个额外的好处,我们可以使用 webpack 的 babel 插件在旧浏览器的代码上运行 babel,而且我们也不必维护该构建脚本。
Note that if Chrome (our browser of choice) started supporting import
for real we'd probably switch to that for development but that wouldn't really change anything. We could still use webpack to make a concatenated file and we could use it run babel over the code for all browsers.
请注意,如果 Chrome(我们选择的浏览器)开始import
真正支持我们,我们可能会切换到它进行开发,但这不会真正改变任何东西。我们仍然可以使用 webpack 来创建一个连接文件,我们可以使用它在所有浏览器的代码上运行 babel。
All of this is gained by not using script tags and using AMD
所有这一切都是通过不使用脚本标签和使用 AMD 获得的