单页应用程序中管理JavaScript的最佳实践

5

我正在开发一个单页应用程序,通过更改哈希值并仅加载和更改页面内容来实现。我正在考虑如何管理每个“页面”可能需要的JavaScript。

我已经编写了一个 History 模块来监控位置哈希值,它可能类似于 domain.com/#/company/about,还有一个 Page 类将使用 XHR 获取内容并将其插入到内容区域中。

function onHashChange(hash) {
    var skipCache = false;
    if(hash in noCacheList) {
        skipCache = true;
    } 
    new Page(hash, skipCache).insert();
}


// Page.js
var _pageCache = {};
function Page(url, skipCache) {

    if(!skipCache && (url in _pageCache)) {
        return _pageCache[url];
    }
    this.url = url;
    this.load();

}

缓存应该让已经加载的页面跳过XHR。我还将内容存储到一个文档片段中,然后在插入新的Page时从文档中提取当前内容,这样浏览器只需要为片段构建DOM一次。
如果页面具有时间敏感数据,则可能希望跳过缓存。
以下是需要决定的事情:被加载的任何页面都很可能具有一些自己的JavaScript来控制页面。例如,如果页面使用选项卡、需要幻灯片展示、具有某种形式的动画、具有ajax表单或其他等等。
最好的方式到底是什么?将脚本标记包含在从XHR返回的文档片段中吗?如果我需要跳过缓存并重新下载片段怎么办?我感觉第二次调用完全相同的JavaScript可能会导致冲突,比如重新声明相同的变量。
更好的方式是否应该是在获取新Page时将脚本附加到中?这将需要原始页面知道每个其他页面可能需要的所有资源。
除了了解包括所有内容的最佳方式之外,我还需要担心内存管理和可能的泄漏,因为将许多不同的JavaScript部分加载到单个页面实例中?

1
你可以从服务器加载第一页,然后其他所有内容都使用XHR(XMLHttpRequest),而不是完整的页面请求。Facebook就是一个例子。 - seanmonstar
jQuery是你的好朋友,给它买杯饮料吧。 - James Westgate
7个回答

1

如果我正确理解了这个情况,您正在尝试获取一个已经为正常导航制作了页面的站点,并且您想通过ajax将它们拉下来,以节省页面重新加载的时间?

然后,当这种情况发生时,您需要不重新加载那些页面的脚本标签,除非它们还没有加载到页面上?

如果是这种情况,您可以尝试在将新的html插入到dom之前从页面中获取所有标签:

//first set up a cache of urls you already have loaded.
var loadedScripts = [];

//after user has triggered the ajax call, and you've received the text-response
function clearLoadedScripts(response){
   var womb = document.createElement('div');
   womb.innerHTML = response;
   var scripts = womb.getElementsByTagName('script');
   var script, i = scripts.length;
   while (i--) {
      script = scripts[i];
      if (loadedScripts.indexOf(script.src) !== -1) {
          script.parentNode.removeChild(script);
      }
      else {
          loadedScripts.push(script.src);
      }
   }

   //then do whatever you want with the contents.. something like:
   document.body.innerHTML = womb.getElementsByTagName('body')[0].innerHTML);

}

1

哦,你真幸运。我刚为自己的项目做了所有这些研究。

1:你应该使用Ben Alman的BBQ哈希事件/管理器: http://benalman.com/projects/jquery-bbq-plugin/

2:要让搜索引擎喜欢你,你需要遵循这个非常清晰的规则集: http://code.google.com/web/ajaxcrawling/docs/specification.html

我发现这个规则有点晚了,不得不放弃了很多我的代码。听起来你也要放弃一些,但作为结果,你会得到更多的收获。

祝你好运!


谢谢你分享那篇关于google.com ajaxcrawling的文章,我一直在寻找它。 - seanmonstar
如果以下是您要查找的内容,请将其标记为答案:NP! - Matrym
我自己也在寻找这个链接,但我认为这并没有回答问题,很抱歉。我更感兴趣的是各种页面所需的Javascript管理、处理新声明的变量、附加和解除事件以及内存管理。 - seanmonstar

0

个人而言,我会传输 JSON 而不是原始的 HTML:

{
    "title": "About",
    "requires": ["navigation", "maps"],
    "content": "<div id=…"
}

这样可以让您发送元数据,比如一组所需脚本,以及内容一起。然后,您可以使用一个脚本加载器(如上面提到的其中之一,或者您自己的加载器),检查已加载的脚本,并下载那些尚未加载的脚本(将它们插入到<head>中),然后再渲染页面。
与其在页面特定的逻辑中内联包含脚本,我建议在需要特殊处理的元素上使用预定义的类、id和属性。您可以触发一个"onrender"事件,或者让每个逻辑部分注册一个在页面渲染或首次加载后由页面加载器调用的回调函数。

0

我从未构建过这样的网站,所以我不知道是否是最佳实践,但我会在响应中放置一些控制信息(如注释或HTTP头),并让加载器脚本处理冗余/依赖性检查并将脚本标签添加到头部。


0

你能控制那些页面被加载吗?如果不能,我建议将加载的页面插入到一个IFrame中。

将页面脚本从它们的上下文中取出并插入到头部或添加到另一个HTML元素中可能会导致问题,除非你确切地知道页面是如何构建的。

如果你完全控制被加载的页面,我建议你将所有的HTML转换为JS。这听起来很奇怪,但实际上,一个HTML->JS转换器并不遥远。你可以从Pure JavaScript HTML Parser开始,然后让解析器输出JS代码,使用JQuery构建DOM。

我曾经在一个Web应用程序上工作时也考虑过这种方法,但现在我把它交给了一个承包商,他把我的纯JS页面转换成了HTML+JQuery,无论什么使他的日常工作更有效率,我都不在乎,但我真的很喜欢那种纯JS Web应用程序的方法,一定会尝试的。


我对页面有控制权。我正在考虑使用JS解析器。但是我已经在PHP中创建了页面,而且由于PHP比JS快得多,所以我只打算返回HTML。 - seanmonstar

0

听起来像是你从头开始创建一个单页应用程序(即不是重构现有网站)。

我能想到的几个选项:

  1. 让服务器控制包含哪些脚本标签。使用XHR请求时传递一个已加载的脚本标签列表,并让服务器确定需要加载哪些其他脚本。
  2. 预先加载所有脚本(可以在页面加载后将它们添加到DOM中以节省时间),然后就忘记它们。对于需要初始化UI的脚本,只需让每个请求的页面调用一个包含调用全局init函数和页面名称的脚本标签。
  3. 让每个请求的页面调用一个JS函数来处理加载/缓存脚本。这个函数可以从全局作用域中访问,并且看起来像这样:require_scripts('page_1_init', 'form_code', 'login_code') 然后让该函数保持一个已加载的脚本列表,并仅为尚未加载的脚本附加DOM脚本标签。

0

你可以使用像YUI Loader、LAB.js或其他类似jaf的脚本加载器。

Jaf提供了一种机制来加载视图(HTML片段)及其相应的JS、CSS文件,以创建单页应用程序。请查看样例待办事项列表应用程序。虽然它还没有完整,但仍有许多有用的库可以使用。


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