在单页应用上管理JavaScript的最佳实践

时间:2010-05-06 16:40:45

标签: javascript ajax singlepage

使用单页应用,我更改哈希并加载并仅更改页面内容,我正在尝试决定如何管理每个“页面”可能需要的JavaScript。

我已经有一个历史模块监视位置哈希,它可能看起来像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。我还将内容存储到documentFragment中,然后在插入新的Page时将当前内容从文档中拉出来,因此浏览器只需要为片段构建一次DOM。

如果页面具有时间敏感数据,则可能需要跳过缓存。

以下是我需要帮助决定的内容:很可能任何加载的页面都会有一些自己的JavaScript来控制页面。就像页面将使用Tabs一样,需要幻灯片放映,有某种动画,有ajax形式或者有什么。

将JavaScript加载到页面的最佳方法是什么?在我从XHR返回的documentFragment中包含脚本标记?如果我需要跳过缓存并重新下载片段,该怎么办?我觉得第二次调用的完全相同的JavaScript可能会导致冲突,比如重新声明相同的变量。

抓住新的Page时,更好的方法是将脚本附加到头部吗?这将要求原始页面知道每个其他页面可能需要的所有资产。

除了知道包含所有内容的最佳方法之外,我不需要担心内存管理,以及将这么多不同的JavaScript位加载到单个页面实例中的可能泄漏吗?

7 个答案:

答案 0 :(得分: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)

噢,小伙子,你好运。我刚刚为自己的项目做了所有这些研究。

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

2:为了让搜索引擎爱你,你需要遵循这套非常明确的规则: http://code.google.com/web/ajaxcrawling/docs/specification.html

我发现这很晚,游戏并不得不废弃我的很多代码。听起来你也不得不放弃一些,但结果会让你得到更多。

祝你好运!

答案 2 :(得分:0)

我从来没有构建过这样的网站,所以我不知道这是不是最好的做法,但我会在响应中加入某种控制信息(如注释或HTTP标头),并让加载器脚本处理冗余/依赖性切换并将脚本标记添加到标题中。

答案 3 :(得分:0)

您是否可以控制正在加载的页面?如果没有,我建议将加载的页面插入IFrame。

将页面脚本从其上下文中删除并将其插入到头部或将其添加到另一个HTML元素可能会导致问题,除非您确切知道页面的构建方式。

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

我实际上刚刚开始使用我开始研究的webapp,但是现在我把它交给了一个承包商,后者将我所有的纯JS页面转换为HTML + JQuery,无论是什么使他的日常生活工作富有成效,我不在乎,但我真的很喜欢那种纯粹的JS webapp方法,并且一定会尝试它。

答案 4 :(得分:0)

对我来说,这听起来像是从一开始就创建了一个单页应用程序(即没有重新分解现有网站)。

我能想到的几个选项:

  1. 服务器控制包含哪些脚本标记。使用XHR请求传递已加载的脚本标记列表,并让服务器整理出需要加载的其他脚本。
  2. 在手前加载所有脚本(可能在页面加载后将它们添加到DOM 中以节省时间),然后忘记它。对于需要初始化UI的脚本,只需让每个请求的页面调用都包含一个脚本标记,该标记使用页面名称调用全局init函数。
  3. 让每个请求的页面调用 JS函数来处理加载/缓存脚本。可以从全局范围访问此函数,如下所示:require_scripts('page_1_init', 'form_code', 'login_code')然后让函数保留已加载脚本的列表,并仅为尚未加载的脚本附加DOM脚本标记。

答案 5 :(得分:0)

您可以使用像YUI Loader,LAB.js或其他类似jaf

的脚本加载器

Jaf为您提供了加载视图(HTML代码段)及其各自的js,css文件以创建单页应用程序的机制。查看示例待办事项列表应用程序。虽然它不完整,但仍然可以使用许多有用的库。

答案 6 :(得分:0)

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

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

这使您可以发送元数据,如所需脚本数组,以及内容。然后,您可以使用脚本加载器(如上面提到的那个)或您自己的脚本加载器来检查已加载的脚本加载器,并在渲染之前下拉那些不加载的脚本加载器(将它们插入<head>)页面。

我不使用脚本内联特定于页面的逻辑,而是在需要特殊处理的元素上使用预定的类,id和属性。你可以触发一个“onrender”事件,或者让每个逻辑片段注册一个渲染回调,你的页面加载器将在第一次渲染或加载页面后调用它。