【问题标题】:Can you execute contained JavaScript in browsers?你可以在浏览器中执行包含的 JavaScript 吗?
【发布时间】:2015-10-20 05:24:37
【问题描述】:

我希望能够在我的网页上运行 JavaScript,并保证可以干净地停止它而不会造成问题。您可以将其视为运行 JavaScript,就好像它包含在 iFrame 中一样,但允许它修改并与根 DOM 交互。这样,如果我删除 iFrame,JS 就会死掉。

用例/理由

我想把任何网页变成一个奇怪的变异 SPA。这意味着采用传统的 HTML、CSS 和 JavaScript,然后自己处理页面切换。为了正确切换页面,避免以前执行的 JS 产生的工件,我需要确保一个页面的 JS 不与下一页的 JS 交互。理想情况下,要切换页面,它会遵循以下通用公式:

  1. 使用 Ember.js 等框架加载 HTML 和 CSS
  2. 在包含的环境中加载所有链接的 JavaScript,但能够修改根 DOM
  3. 当用户点击一个链接时,停止所有正在运行的 JavaScript 并返回到第 1 步。

我的想法

我已经运行测试,实际上在全屏 iframe (like this) 中加载网页,这达到了我在执行 JavaScript 时想要的包含级别,但它有严重的性能损失。我想要包含的 JavaScript,性能损失最小。

我的一个想法是在下载 JavaScript 之后动态替换实际代码。我会将代码更改为引用Window.parent,而不是引用Window。

我不喜欢使用 iFrames 的想法,但它似乎是你可以在 JavaScript/浏览器中获得的最接近“容器”的东西。我喜欢其他选择。

相关?

github.com/codeschool/javascript-sandbox

instantclick.io/

影子 DOM?

迷你跟进:

构建这样的应用程序是否可行,可以正确处理 JS 生命周期和页面切换?

【问题讨论】:

  • 没办法。与 DOM 交互的 JS 只有在 DOM 死亡时才会死亡。因此,这在很大程度上取决于 JS 在您的每个页面上究竟做了什么,以及 DOM 的多少/哪些部分需要被换出。
  • 这是否意味着对于我的用例,可能不需要删除 JavaScript?如果 JS 引用了我然后换出的特定节点,那么 JS 会死吗?否则JS会完好无损?这对我有利吗?还是我在切换页面时还要担心奇怪的 JS 交互?
  • 只要你的 JavaScript 是正确自包含/模块化的,并且具有正确的拆解逻辑,你就不必担心“奇怪的 JS 交互”。例如,您在帖子中提到了 EmberJS,它会自动处理大部分拆解逻辑,因此您需要处理的只是删除手动添加的事件侦听器。
  • @KarlFloersch:我的意思是,如果您的 JS 仅被移除的 DOM 节点引用(例如通过事件侦听器),那么它就会死掉。但是,如果您的 JS 确实创建了某种全局对象(不会被轻易覆盖),或者它确实使用了 setInterval 左右(可能是在一个永无止境的动画中?),那么 JS 将保留分离的 DOM 节点并创建一个内存泄漏。所以:这取决于。
  • @PeteTNT 如果您使用 Ember.js,您会说绝大多数网站(例如 wordpress 网站)不需要运行完全包含的 JS,因为大部分拆解逻辑已经完成?我想我可能会解决这个问题,看看情况如何。还有一种简单的方法可以删除事件侦听器吗?

标签: javascript dom iframe ember.js containers


【解决方案1】:

脚本一旦加载就无法卸载。但是你可以在一个对象中封装一些脚本,然后创建或销毁这个对象。

例如:

var Robot = function(){
    return{
        sayHello : function(){
            alert("Hello!");
        },
        doSomethingElse : function(){
            alert("I'm doing something else");
        }
    }
}

robot = new Robot();

robot.sayHello(); // Actually alerts "Hello!"

robot = null; // the robot is destroyed.

在您的情况下,如果您通过 ajax 加载脚本,请在对象中说这段脚本:

{
    sayHello : function(){
        alert("Hello!");
    },
    doSomethingElse : function(){
        alert("I'm doing something else");
    }
}

然后您可以将此脚本封装在一个函数中:

var Robot = null,
    robot = null;

$.get('scriptURL', function(ajaxedScriptObject){
    Robot = function(){ return ajaxedScriptObject; };
    createRobot();
})

function createRobot(){
    robot = new Robot();
    sayHello();
    destroyRobot();
}

function sayHello(){
    robot.sayHello(); // Should alert "Hello!" :)
}

function destroyRobot(){
    robot = null;
}

【讨论】:

  • 这行得通吗:我下载了一堆带有几个 Ajax 调用的脚本。然后我构建一个包装对象并用我刚刚下载的 JS 填充该对象。我实例化了这个新对象,它又运行所有包含的脚本。一旦用户离开此页面,我就会删除该对象。
  • 我认为它可以工作。这听起来有点困难,但可行。我不能确定,我以前从来没有做过这样的事情。如果您的 ajax 调用使用您的脚本返回一个对象,您可以定义 Robot = function(){ return ajaxScriptObject; }
  • 我已经编辑了我的答案,试图让我的代码适应你的问题。
  • don't use delete for this。确实,您需要implicitly created through assignment 的全局变量,但这是一件可怕 的事情。
  • 作为替代方案,只需设置robot = null。我也想知道为什么我的回答被否决了。我已经编辑过了。
最近更新 更多