JavaScript阻止脚本执行

6

我需要做类似于这样的事情:

  • 执行一段代码
  • 开始加载一个图像并阻止脚本执行
  • 当图像加载完毕后,恢复执行
  • 执行剩下的代码

我知道最简单的方法是在图像的 onload 事件上分配一个函数,然后在函数中执行其余的代码,但如果可能的话,我希望有一种“线性”行为来阻止脚本执行,然后恢复它。那么,是否有一种跨浏览器的方法来实现这个呢?

5个回答

3

唯一阻止脚本执行的方法是使用循环,这也会锁定大多数浏览器并防止与您的网页进行任何交互。

Firefox、Chrome、Safari、Opera和IE 全部 支持complete属性,在HTML5中最终被标准化。这意味着您可以使用while循环来阻止脚本执行,直到图像下载完成。

var img = new Image();
img.src = "/myImage.jpg";
document.body.appendChild(img);
while (!img.complete) 
{
    // do nothing...
}

// script continues after image load

话虽如此,我认为你应该寻找在不锁定浏览器的情况下实现目标的方法。


我同意这是一种不好的方式,但我认为这也是唯一的方式。也许我可以给用户选择在阻止脚本执行和在图像加载时调用加载函数之间的可能性。 - mck89
@mck89:我很难相信这是唯一的方法。老实说,我从未遇到过在JavaScript中需要锁定脚本的情况;总有一种方法(例如暂时覆盖函数)可以异步地完成任务。毕竟,您控制着页面上的脚本。也许您可以发布另一个问题,更详细地描述您的问题? - Andy E
@mck89:complete 属性适用于 Gecko 和 IE,也可能适用于其他浏览器。如果您坚持阻止脚本执行,请查看我的更新。 - Andy E
是的,我想我会使用类似这样的东西,谢谢你的帮助。 - mck89

1

我不会尝试完全阻止脚本执行,因为这可能会使浏览器变慢,甚至会提示用户脚本执行时间过长。

你可以通过使用事件来完成工作来“线性化”你的代码。你需要在函数中添加一个超时,因为图像可能永远无法加载。

例如:

var _img = null; 
var _imgDelay = 0;
var _finished = false;

function startWork(){
   _img = document.createElement('img');
   _img.onload = onImgLoaded;
   _img.src = 'yourimg.png';

   // append img tag to parent element here

   // this is a time out function in case the img never loads,
   // or the onload event never fires (which can happen in some browsers) 
   imgTimeout();   
}

function imgTimeout(){
   if (_img.complete){
      // img is really done loading
      finishWork();
   }
   else{
      // calls recursively waiting for the img to load
      // increasing the wait time with each call, up to 12s
      _imgDelay += 3000;

      if (_imgDelay <= 12000){ // waits up to 30 seconds
         setTimeout(imgTimeout, _imgDelay);
      }
      else{
         // img never loaded, recover here.
      }
   }
}

function onImgLoaded(){
   finishWork();
}

function finishWork(){
   if (!_finished){
      // continue here
      _finished = true;
   }
}

你确定可以使用setTimeout停止执行吗? - mck89
这并不会停止代码执行,它允许您等待图像完成加载后再进行任何其他工作。通过将剩余的代码移动到finishWork函数中,您可以“停止”自己的代码执行。 - FlashXSFX

1

你可以使用XMLHttpRequest并使用同步模式。

var url = "image.php?sleep=3";
var img = new Image;
var sjax = new XMLHttpRequest();
img.src = url;
sjax.open("GET", url, false);
sjax.send(null);
alert(img.complete);

这里的技巧是我们加载同一张图片两次,首先使用Image对象,然后使用同步模式中的ajax。 Image对象不是必需的,我只是假设这是您想要加载它的方式。关键在于,如果ajax完成,则图像将完全下载并在浏览器缓存中。因此,该图像也可供Image对象使用。
这假设图像使用缓存友好的http标头提供服务。否则,它的行为可能因不同的浏览器而异。

1
如果您不介意有一个预处理步骤,可以尝试使用Narrative Javascript
image.onload = new EventNotifier();
image.onload.wait->();

这是一个很棒的项目,但我正在尝试使用纯JavaScript构建一个简单的应用程序...而且我对Java一无所知:) - mck89
@mck89:预处理后,您将获得纯JavaScript。 - kennytm
是的,我知道,但我更喜欢只使用JavaScript。 - mck89
据我所知,所有的叙事性JavaScript所做的就是为您创建必要的回调函数。它不会停止脚本执行(因为脚本的其他部分仍然可以运行)。 - Andy E
@Andy:你认为 OP 想要一个检查循环 (while(!image.loaded){}) 吗? - kennytm
@KennyTM:那不是我说的话(而我的回答说这是唯一阻止脚本执行的方法)。我认为 OP 应该改变他的代码,使用回调/事件处理程序来工作。 - Andy E

1

这个建议不完全符合您的要求,但我提供它作为可能的替代方案。

创建一个带有所需背景图片的CSS类。当您的应用程序启动时,将此CSS类分配给一个DIV,该DIV要么被隐藏在视线之外,要么大小为零像素。这将确保从服务器加载图像。当您想要加载图像(如上面的第二步)时,请使用您创建的CSS类;这将快速发生。也许足够快,您无需阻止后续代码执行?


是的,这可能是一种不错的预加载图像的方法,但我并没有在应用程序开始时加载图像。 - mck89
我理解,但是如果你创建了一个带有background-image属性的CSS类,并将该类分配给一个虚拟DIV,那么你将在应用程序开始时加载该图像。 - Upperstage

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