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

发布于 2024-08-31 12:48:15 字数 1129 浏览 6 评论 0原文

在单页应用程序中,我更改哈希并加载并仅更改页面的内容,我试图决定如何管理每个“页面”可能需要的 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 来控制页面。就像页面是否使用选项卡、需要幻灯片放映、有某种动画、有 ajax 表单或诸如此类的东西。

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

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

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

With a single page app, where I change the hash and load and change only the content of the page, I'm trying to decide on how to manage the JavaScript that each "page" might need.

I've already got a History module monitoring the location hash which could look like domain.com/#/company/about, and a Page class that will use XHR to get the content and insert it into the content area.

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

}

The cache should let pages that have already been loaded skip the XHR. I also am storing the content into a documentFragment, and then pulling the current content out of the document when I insert the new Page, so I the browser will only have to build the DOM for the fragment once.

Skipping the cache could be desired if the page has time sensitive data.

Here's what I need help deciding on: It's very likely that any of the pages that get loaded will have some of their own JavaScript to control the page. Like if the page will use Tabs, needs a slide show, has some sort of animation, has an ajax form, or what-have-you.

What exactly is the best way to go around loading that JavaScript into the page? Include the script tags in the documentFragment I get back from the XHR? What if I need to skip the cache, and re-download the fragment. I feel the exact same JavaScript being called a second time might cause conflicts, like redeclaring the same variables.

Would the better way be to attach the scripts to the head when grabbing the new Page? That would require the original page know all the assets that every other page might need.

And besides knowing the best way to include everything, won't I need to worry about memory management, and possible leaks of loading so many different JavaScript bits into a single page instance?

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

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

发布评论

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

评论(7

策马西风 2024-09-07 12:48:15

如果我正确理解了这种情况,您正在尝试访问一个当前已经为正常导航制作页面的网站,并且您想通过 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);

}

If I understand the case correctly, you are trying to take a site that currently has pages already made for normal navigation, and you want to pull them down via ajax, to save yourself the page-reload?

Then, when this happens, you need to not reload the script tags for those pages, unless they're not loaded onto the page already?

If that is the case, you could try to grab all the tags from the page before inserting the new html into the 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);

}
白况 2024-09-07 12:48:15

噢,孩子,你运气好吗?我只是为我自己的项目做了所有这些研究。

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

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

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

祝你好运!

Oh boy are you in luck. I just did all of this research for my own project.

1: The hash event / manager you should be using is Ben Alman's BBQ:
http://benalman.com/projects/jquery-bbq-plugin/

2: To make search engines love you, you need to follow this very clear set of rules:
http://code.google.com/web/ajaxcrawling/docs/specification.html

I found this late and the game and had to scrap a lot of my code. It sounds like you're going to have to scrap some too, but you'll get a lot more out of it as a consequence.

Good luck!

没有你我更好 2024-09-07 12:48:15

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

I have never built such a site so I don't know if that is nbest practice, but I would put some sort of control information (like a comment or a HTTP header) in the response, and let the loader script handle redundancy/dependency cheching and adding the script tags to the header.

撕心裂肺的伤痛 2024-09-07 12:48:15

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

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

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

事实上,我不久前就打算在我开始开发的一个网络应用程序上走这条路,但现在我把它交给了一个承包商,他将我所有的纯 JS 页面转换为 HTML+JQuery,无论是什么使他的日常工作富有成效,我不在乎,但我真的很喜欢纯 JS Web 应用程序方法,并且一定会尝试它。

Do you have control over those pages being loaded? If not, I would recommend inserting the loaded page in an IFrame.

Taking the page scripts out of their context and inserting them in the head or adding them to another HTML element may cause problems unless you know exactly how the page is build.

If you have full control of the pages being loaded, I would recommend that you convert all your HTML to JS. It may sound strange but actually, a HTML->JS converter is not that far away. You could start of with Pure JavaScript HTML Parser and then let the parser output JS code, that builds the DOM using JQuery for example.

I was actually about to go down that road for a while ago on a webapp that I started working on, but now I handed it over to a contractor who converted all my pure JS pages into HTML+JQuery, whatever makes his daily work productive, I dont care, but I was really into that pure JS webapp approach and will definitely try it.

自控 2024-09-07 12:48:15

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

我能想到的几个选项:

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

To me it sounds like you are creating a single-page app from the start (i.e. not re-factoring an existing site).

Several options I can think of:

  1. Let the server control which script tags are included. pass a list of already-loaded script tags with the XHR request and have the server sort out which additional scripts need to be loaded.
  2. Load all scripts before-hand (perhaps add them to the DOM after the page has loaded to save time) and then forget about it. For scripts that need to initialize UI, just have each requested page call include a script tag that calls a global init function with the page name.
  3. Have each requested page call a JS function that deals with loading/caching scripts. This function would be accessible from the global scope and would look like this: require_scripts('page_1_init', 'form_code', 'login_code') Then just have the function keep a list of loaded scripts and only append DOM script tags for scripts that haven't been loaded yet.
药祭#氼 2024-09-07 12:48:15

您可以使用 YUI Loader、LAB.js 等脚本加载器或

Jaf 为您提供 的 jaf 等其他脚本加载器具有加载视图(HTML 片段)及其各自的 js、css 文件的机制来创建单页应用程序。查看示例待办事项列表应用程序。尽管它并不完整,但仍然有很多有用的库可以使用。

You could use a script loader like YUI Loader, LAB.js or other like jaf

Jaf provides you with mechanism to load views (HTML snippets) and their respective js, css files to create single page apps. Check out the sample todo list app. Although its not complete, there's still a lot of useful libraries you can use.

岁月染过的梦 2024-09-07 12:48:15

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

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

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

我不会在特定于页面的逻辑中包含内联脚本,而是在需要特殊处理的元素上使用预先确定的类、id 和属性。您可以触发“onrender”事件,或者让每个逻辑块注册一个渲染回调,页面加载器将在页面首次渲染或加载后调用该回调。

Personally, I would transmit JSON instead of raw HTML:

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

This lets you send metadata, like an array of required scripts, along with the content. You'd then use a script loader, like one of the ones mentioned above, or your own, to check which ones are already loaded and pull down the ones that aren't (inserting them into the <head>) before rendering the page.

Instead of including scripts inline for page-specific logic, I'd use pre-determined classes, ids, and attributes on elements that need special handling. You can fire an "onrender" event or let each piece of logic register an on-render callback that your page loader will call after a page is rendered or loaded for the first time.

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