代码之家  ›  专栏  ›  技术社区  ›  James

javascript竞赛条件

  •  1
  • James  · 技术社区  · 16 年前

    我正在调用一个javascript函数,它将iframe的不透明度设置为未知的连续次数。基本上,这将α从0变为100。 这是密码

    
       function setAlpha(value)
       {
           iframe.style.opacity = value * .01;
           iframe.style.filter = 'alpha(opacity =' + val + ')';
       }
    
    

    我的问题是它第一次在ie(7)中工作,而不是在firefox(3.02)中。在Firefox中,我得到一个延迟,然后contentdocument以100的不透明度出现。如果我在其中添加了一个警报,那么我猜这是一个竞争条件(尽管我认为javascript是单线程的),并且setAlpha函数在最后一个函数完成执行之前被调用。 任何帮助都将不胜感激。我读过“避免javascript竞争条件”一文,但我认为这有点不同(另外,我不知道如何将该示例应用于此)。

    4 回复  |  直到 16 年前
        1
  •  5
  •   jcampbell1    16 年前

    问题是,大多数浏览器在javascript执行暂停之前不会重新绘制。

    正如其他人所建议的,这可以通过使用setTimeout来解决。但是,我建议使用jQuery或任何javascript库来制作动画。运行setTimeout 100次是个坏主意,因为动画的长度将根据浏览器和用户计算机的速度而变化。制作动画的正确方法是指定动画应该持续多长时间,并检查系统时间以确定动画应该进行多长时间。

    function fadeIn(elem,animation_length) {
       var start = (new Date()).getTime();
    
       var step = function() {
          window.setTimeout(function() {
            var pct = ((new Date()).getTime() - start)/animation_length;
            elem.style.opacity = Math.min(pct,1);
            if (pct < 1) 
               step();
          },20);
       };
       step();
    }
    

    [编辑:]上面的代码只是为了说明如何根据系统时钟而不是简单的间隔来制作动画。请使用库来制作动画。上面的代码对IE不起作用,因为IE使用“filter:opacity(xx)”而不是“opacity”。库将为您处理这个问题,并提供一些不错的特性,如完成事件和取消动画的能力。

        2
  •  1
  •   olliej    16 年前

    Javascript不跨多个线程运行,因此您可以安全地避免竞争条件(忽略Safari和Firefox:D中即将提供的工作线程支持)。

    简单的问题是,如何多次调用setAlpha、firefox、safari和opera都会合并样式表更新——例如,当js运行时,它们不会重新绘制甚至重新调用样式信息,除非必须这样做。所以他们只会在JS完成的情况下绘画。

    所以如果你在做

    while(...) setAlpha(...)
    

    它们不会更新,您可能需要使用setTimeout触发多个不同的调用来更新样式。

    另一种方法是使用一个库,如jQuery、mootools等,我模糊地记得这些库提供了一种简化的机制来执行这些类型的动画和转换。作为一个额外的好处,我相信至少有几个库在可用时也会使用webkit转换和动画css规则(例如Safari和i 认为 最新的firefox版本)

    [编辑:警告:我并没有真正使用过这些库,我只是读到它们应该做什么。我的站点在lynx中呈现的内容与其他浏览器相同,因为我无法设计出一个纸袋:D]

        3
  •  0
  •   Breton    16 年前

    你是在使用setTimeout还是一个紧循环?如果只使用循环调用函数,则切换到使用setTimout。

    例子:

       function setAlpha(value)
       {
           iframe.style.opacity = value * .01;
           iframe.style.filter = 'alpha(opacity =' + val + ')';
           if(value < 100 ) {
           setTimeout(function () {setAlpha(value+1)},20);
           }
       }
       setAlpha(0);
    

    因为你知道,不仅仅是javascript是单线程的。全是该死的浏览器。如果你的javascript陷入困境,你就会挂断整个浏览器。因此浏览器暂停等待javascript完成,甚至没有机会更新屏幕,而您的代码正在快速更改一些dom值。

        4
  •  0
  •   Kenan Banks    16 年前

    有些浏览器足够聪明,可以延迟对DOM的更改,直到调用堆栈为空。

    这通常是一件聪明的事。例如,如果调用一个将元素更改为黄色的函数,并立即调用一个将同一元素更改回其原始状态的函数,则浏览器不应浪费时间进行更改,因为更改应该发生得太快,以至于用户无法察觉。

    这个 setTimeout(func, 0) 技巧通常用于强制Javascript延迟 func 直到调用堆栈为空。

    代码中:

    function setAlpha(opacity){
       some_element.style.opacity = opacity;
    }
    
    /** 
    * This WON'T work, because the browsers won't bother reflecting the 
    * changes to the element's opacity until the call stack is empty, 
    * which can't happen until fadeOut() returns (at the earliest)
    **/
    function fadeOut(){
        for (var i=0; i<10; i++){
            setAlpha(0.1*i);    
        }
    }
    
    /** 
    * This works, because the call stack will be empty between calls
    * to setAlpha()
    **/
    function fadeOut2(){
        var opacity = 1;
        setTimeout(function setAlphaStep(){
            setAlpha(opacity);
            if (opacity > 0){
                setTimeout(setAlphaStep, 10);        
            }
            opacity -= 0.1;  
        }, 0);
    }
    

    所有这些可以归结为一个很好的借口,可以使用许多javascript库中的一个来为您处理这些棘手的事情。

    编辑:这里有一个 good article on the tricky Javascript call stack