JavaScript用户界面,requirejs和未样式化内容的闪烁问题

3

我目前主要使用requirejs,因为它的资源加载器。我喜欢它管理回退的方式。

我的JavaScript应用程序并不复杂,只是一些jQuery UI小部件和其他细微调整。

在开始使用requirejs之前,我甚至不知道FOUC是什么。这相当明显,所以目前我正在避免使用以下方法:

var protect_from_FOUC = function(element) {
    if(typeof element === 'string') {
        element = document.querySelector(element);
    }
    element.classList.add('ui-helper-hidden');
};

<div id="main" class="main_block" role="main">
<!-- a block affected by FOUC -->
</div>
<script>protect_from_FOUC('#main');</script>

在我的脚本中:

require(['jquery', 'jquery-ui' /*, ...*/], function($) {

var recover_from_FOUC = function(element) {
    $(element).show({
        effect: 'blind',
        duration: 200
    }).removeClass('ui-helper-hidden');
};

$(document).ready(function() {

    // Themed buttons:
    $(':button, :submit, :reset, .button').button();
    // ... Some other similar changes
    recover_from_FOUC('#main');

});  // document.ready

});  // require

这是我所拥有的最好的资源,所有我在网络上找到的相关主题的在线资源都建议采取类似的方法。我的问题是,考虑到我谈论的只是影响UI的脚本,是否值得使用requirejs?正如我所说,我想继续使用它的资源回退系统,但整个“FOUC修补程序”似乎是适得其反的。每个jQuery UI示例都在头部包含脚本,但互联网上的每个人都建议将脚本包含在body结束前或使用异步加载器。这个建议仅适用于“非UI”脚本吗?在这种情况下哪种方式最好?请注意,尽管接近,这不仅仅是另一个“如何避免FOUC问题”的问题。编辑:添加了包含在我的页面中的外部文件和我的require.config:
<!-- This is in my head right below the meta tags and exactly in this order -->
<link rel="shortcut icon" href="images/favicon.ico"/>
<!-- Keep before the site css to allow overriding jquery's style -->
<link rel="stylesheet" href="style/lib/jquery-ui/ui-lightness/jquery-ui.css"/>
<link rel="stylesheet" href="style/lib/chosen/chosen.css"/>
<link rel="stylesheet" href="style/lib/icheck/minimal/yellow.css">
<link rel="stylesheet" href="style/reset.css">
<link rel="stylesheet" href="style/style.css"/>

<!-- Here I have the definition of `protect_from_FOUC` in an inline script -->

<script data-main="js/main" src="js/lib/require.js"></script>

在 main.js 文件中:
require.config({
    paths: {
        // Common:
        'jquery': ['//code.jquery.com/jquery-2.0.3.min', 'lib/jquery'],
        'sugar': ['//cdnjs.cloudflare.com/ajax/libs/sugar/1.3.9/sugar.min', 'lib/sugar'],

        // UI:
        'jquery-ui': ['//code.jquery.com/ui/1.10.3/jquery-ui.min', 'lib/jquery-ui'],
        'autosize': ['//cdnjs.cloudflare.com/ajax/libs/autosize.js/1.17.1/autosize-min', 'lib/jquery.autosize'],
        'chosen': ['//cdnjs.cloudflare.com/ajax/libs/chosen/0.9.15/chosen.jquery.min', 'lib/chosen.jquery'],
        'icheck': ['lib/jquery.icheck'],

        // django i18n:
        'gettext': [translations_url + '?noext']
    },
    shim: {
        'jquery-ui': {
            deps: ['jquery']
        },
        'autosize': {
            deps: ['jquery']
        },
        'chosen': {
            deps: ['jquery']
        },
        'icheck': {
            deps: ['jquery']
        }
    }
});

require(['style', 'interaction']);

你是否正在将requirejs脚本优化为单个文件?这并不一定会消除FOUC(因为仍然需要加载该单个JS文件),但可能会减少它。 - Paul Grime
@PaulGrime 还没有。这在 requirejs 的文档中吗? - Adrián
1
可以在这里查看 - http://requirejs.org/docs/optimization.html。这可能有助于解决 FOUC 问题,但会受到许多因素的影响,比如页面加载了多少 CSS、JS 和其他资源。 - Paul Grime
1
是的,外部CSS可以阻止渲染,就像外部JS可以阻止文档解析一样。http://remysharp.com/2011/06/08/link-elements-block-dom-parsing-too/ - Paul Grime
1
我的意思是外部加载,作为单独的资源加载,而不是内联CSS。无论是CDN还是您的“本地”服务器都可能遇到延迟,尽管延迟的细节(例如延迟)会有所不同。 - Paul Grime
显示剩余3条评论
2个回答

3

为什么要在</body>之前放置脚本?因为它们会阻塞解析。

这很糟糕,特别是考虑到您的用例,其中页面上可能有很多内容等待解析和渲染,除了您通过Javascript包含的内容。

将脚本放在最后可以使直接包含在HTML中的所有内容都能够愉快地解析和渲染,而无需等待任何脚本(及其整个请求 -> 解析 -> 执行周期)。

然而,这种策略存在一个问题。那就是将脚本标签堆叠在末尾不允许进行良好(或者说任何?)依赖管理。这是requirejs创建的主要原因之一(还有其他目的,如代码封装、版本/回退、模板插件等)。

您正在使用requirejs以有效地管理否则将很难管理的目的,因此我肯定会说在这种情况下使用requirejs是“值得的”。

至于您对“FOUC补丁”似乎是适得其反的评论,我不确定您为什么认为如此。请考虑补丁为您提供的内容:平滑加载的UI和未阻塞的HTML。将阻塞脚本放在头部可能是一个有效的决定,但仅当页面上的大多数内容都依赖于尽快加载它们时才是如此。这很少发生(实际上,在演示/开发用途之外,这是一种反模式)。

考虑用户体验,特别是考虑到有些过时的智能手机具有缓慢的连接/缓慢的JS解析/执行速度。与让这些用户在空白屏幕上停留3-5秒以上相比,异步加载可以使您的感知加载时间更快。然后,当脚本最终可用时,可以使用FOUC补丁显示UI效果和其他功能。

因此,您可以通过异步脚本提供看似快速的页面加载,并在加载时增强JS,同时使用requirejs进行依赖管理/智能资源回退。听起来不错。


好的回答。你对FOUC补丁提出了一些不错的观点。谢谢你。 - Adrián
非常欢迎。我还记得一开始需要一个补丁才能正确显示的感觉是多么不直观。异步是一个强大的武器 ;) - Wyatt
第一段中的“paean”是什么意思?这是一个打字错误吗? - Gili
赞歌是一首赞美之歌……我承认这是相当华丽的语言。http://www.merriam-webster.com/dictionary/paean - Wyatt

1
作为外部CSS阻止渲染的跟进示例。以下页面的渲染将被缓慢的外部样式表阻止(在我测试过的Chrome和FF中)。
<!doctype html>

<html>

<head>
    <style>body { background: white; }</style>
    <link rel="stylesheet" type="text/css" href="http://deelay.me/0/http://rawgithub.com/gitgrimbo/6487200/raw/red.css">
    <link rel="stylesheet" type="text/css" href="http://deelay.me/5000/http://rawgithub.com/gitgrimbo/6487200/raw/blue.css">
</head>

<body>
    <h1>Top header</h1>

    <script>console.log(new Date()); document.write(new Date());</script>

    <h1>Bottom header</h1>
</body>

</html>

但是,如果将这两个<link>元素移动到页面主体(作为<body>的第一个元素),那么从我在Chrome和FF中所看到的情况来看...

在Chrome中,行为与<link>元素位于文档的<head>时相同。

在FF中,有时会在蓝色之前看到5秒钟的红色背景,有时会在蓝色之前看到一闪而过的红色。我不确定为什么会这样。

阻止脚本?

似乎由于CSS延迟,Chrome和FF也会阻止<script>块的运行。我也不确定为什么会这样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接