Require.js 和简单地创建一个

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

遇见了你 2024-10-23 03:38:19

与简单地在 DOM 中创建元素相比,Require.JS 具有哪些优势?

在您的示例中,您异步创建脚本标记,这意味着您的 needMe() 函数将在 need_me.js 文件完成加载之前调用。这会导致未定义函数的情况下出现未捕获的异常。

相反,为了使您的建议真正起作用,您需要执行以下操作:

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

}

可以说,使用 RequireJS 等包管理器或使用上面演示的纯 JavaScript 策略可能是也可能不是最好。虽然您的 Web 应用程序可能加载速度更快,但调用网站上的功能和特性会更慢,因为这需要等待资源加载才能执行该操作。

如果将 Web 应用程序构建为单页应用程序,那么请考虑人们实际上不会经常重新加载页面。在这些情况下,预加载所有内容将有助于使实际使用应用程序时的体验看起来更快。在这些情况下,您是对的,只需在页面的头部或正文中包含脚本标记即可加载所有资源。

但是,如果构建的网站或 Web 应用程序遵循更传统的模型(从一个页面转换到另一个页面,导致资源重新加载),则延迟加载方法可能有助于加速这些转换。

What advantages does Require.JS offer in comparison to simply creating a element in the DOM?

In your example, you're creating the script tag asynchronously, which means your needMe() function would be invoked before the need_me.js file finishes loading. This results in uncaught exceptions where your function is not defined.

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.

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 using the 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.

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.

思念绕指尖 2024-10-23 03:38:19

这是 ajaxian.com 上一篇关于为什么使用它的好文章:

RequireJS: 异步 JavaScript 加载

  • 某种#include/import/require
  • 能够加载嵌套依赖项,
  • 方便开发人员使用,但由有助于部署的优化工具提供支持

Here is the nice article on ajaxian.com as to why use it:

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
青柠芒果 2024-10-23 03:38:19

使用 RequireJS 有意义的其他一些非常尖锐的原因:

  1. 对于大型项目来说,管理自己的依赖关系很快就会崩溃。
  2. 您可以拥有任意数量的小文件,并且不必担心跟踪依赖项或加载顺序。
  3. RequireJS 可以在不接触窗口对象的情况下编写完整的模块化应用程序。

摘自 rmurphey 在本要点中的评论

学习和适应抽象层可能是一场噩梦,但当它服务于目的并且做得很好时,它就有意义了。

Some other very pointed reasons why using RequireJS makes sense:

  1. Managing your own dependencies rapidly falls apart for sizable projects.
  2. You can have as many small files as you want, and don't have to worry about keeping track of dependencies or load order.
  3. RequireJS makes it possible to write an entire, modular app without touching window object.

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.

梦一生花开无言 2024-10-23 03:38:19

这是一个更具体的例子。

我正在处理一个有 60 个文件的项目。我们有两种不同的运行模式。

  1. 加载一个串联版本,1 个大文件。 (生产)

  2. 加载所有 60 个文件(开发)

我们使用加载器,因此网页中只有一个脚本

<script src="loader.js"></script>

,默认为 mode#1(加载一个大文件)串联文件)。为了运行模式#2(单独的文件),我们设置了一些标志。它可以是任何东西。查询字符串中的键。在这个例子中,我们只是做这个

<script>useDebugVersion = true;</script>
<script src="loader.js"></script>

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");
}

构建脚本只是一个看起来像这样的 .sh 文件

cat > large-concantinated.js app.js somelib.js someotherlib.js anotherlib.js

等等...

如果添加一个新文件,我们可能会使用模式#2,因为我们在进行开发时,我们必须向 loader.js 添加 injectScript("somenewfile.js")

,然后在生产中,我们还必须向构建脚本添加 somenewfile.js。我们经常忘记这一步,然后收到错误消息。

通过切换到 AMD,我们不必编辑 2 个文件。保持 loader.js 和构建脚本同步的问题消失了。使用r.jswebpack它可以只读取代码来构建large-concantinated.js

它还可以处理依赖关系,例如我们有 2 个文件 lib1.js 和 lib2.js 加载,像这样

injectScript("lib1.js");
injectScript("lib2.js");

lib2 需要 lib1。它的内部代码可以执行类似的操作

lib1Api.installPlugin(...);

,但由于注入的脚本是异步加载的,因此无法保证它们会按正确的顺序加载。这两个脚本不是 AMD 脚本,但使用 require.js 我们可以告诉它它们的依赖项

require.config({
    paths: {
        lib1: './path/to/lib1',
        lib2: './path/to/lib2',
    },
    shim: {
        lib1: {
            "exports": 'lib1Api',
        },
        lib2: {
            "deps": ["lib1"],
        },
    }
});

我使用 lib1 的模块我们这样做

define(['lib1'], function(lib1Api) {
   lib1Api.doSomething(...);
});

现在 require.js 将为我们注入脚本,并且在加载 lib1 之前它不会注入 lib2我们告诉它 lib2 依赖于 lib1。在 lib2 和 lib1 都加载之前,它也不会启动使用 lib1 的模块。

这使得开发变得更好(没有构建步骤,不用担心加载顺序),并且使得生产变得更好(不需要为每个添加的脚本更新构建脚本)。

作为额外的好处,我们可以使用 webpack 的 babel 插件在旧浏览器的代码上运行 babel,而且我们也不必维护该构建脚本。

请注意,如果 Chrome(我们选择的浏览器)开始真正支持 import,我们可能会转而使用它进行开发,但这不会真正改变任何事情。我们仍然可以使用 webpack 来制作串联文件,并且可以使用它在所有浏览器的代码上运行 babel。

所有这一切都是通过不使用脚本标签并使用 AMD 获得的

Here's a more concrete example.

I'm working in a project with 60 files. We have 2 different modes of running it.

  1. Load a concatenated version, 1 large file. (Production)

  2. Load all 60 files (development)

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

<script>useDebugVersion = true;</script>
<script src="loader.js"></script>

loader.js looks something like this

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

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

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.

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

It can also deal with dependencies, for example we had 2 files lib1.js and lib2.js loaded like this

injectScript("lib1.js");
injectScript("lib2.js");

lib2 needs lib1. It has code inside that does something like

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

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

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.

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.

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.

All of this is gained by not using script tags and using AMD

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文