如何在if循环内仅执行一次某个操作?

3

编辑(更具体):

我有以下情况。我正在使用JavaScript构建一个实验性的合成器界面。我正在使用howler.js插件来处理音频。 这个想法是,当满足某个条件时播放声音。我有一个存储变量,其值通过的标题而改变。 我使用compass.js。它有一个叫做heading的变量。

$(function(){

    Compass.watch(function (heading) {
      $('.degrees').text(Math.floor(heading) + '°');
      $('#rotate').css('-webkit-transform', 'rotate(' + (-heading) + 'deg)');

       if (heading >= 10 && heading <= 30) {
       sound.play("myFirstSound"); 
       } 
       else if (heading >= 31 && heading <= 60) {
       sound.play("mySecondSound");
       } else { etc etc...
       });
});

即使标题是恒定的,.play命令也会被反复执行,导致音频引擎耗尽内存。如何只执行if循环内的命令一次?我无法在指南针函数之外访问heading的值。我总是收到“var heading不存在”的错误提示。

4
我看不到你的代码中有循环...我需要自己想象吗? - KIKO Software
IF不是一个循环,而是条件语句,如果这是你想说的。 - lshettyl
1
如果你不知道循环,但似乎在编写超出你能力范围的程序,我认为你的if语句可能被多次触发,这可能是因为它们被放在某种循环中。也许是在一个经常被触发的函数内部。 - Jared Teng
哦,是的。我的代码确实在一个包含不断变化的变量并与插件通信的jQuery函数中。那么将我的if逻辑从函数中取出可能会阻止它无休止地触发sound.play()吗?JaredT,是的,这超出了我能力范围之外。但是超出了我应该做的事情吗?我正在努力学习。 - ifthisthenthat
如果触发器是由用户交互引起的,那么它怎么可能一遍又一遍地运行呢?也许是用户的问题:)) 显示if语句是如何被触发的... - Jared Teng
显示剩余5条评论
6个回答

4

拿一个布尔变量,比如

var checkOnce= false;
if (myVariable >= 10 && myVariable <= 30) {
checkOnce=true;
    sound.play("myFirstSound"); 
    } 
    else if (myVariable >= 31 && myVariable <= 60) {
checkOnce=true;
    sound.play("mySecondSound");
    } else { etc etc...

在循环中检查checkOnce的值。循环将一直运行,直到checkOnce=false。


OP想要一个连续的循环,当myVariable的值改变时播放不同的声音...这只是循环一次... - Jordi Castilla

3
创建一个布尔标志boolean flag,只有当其为false时才播放声音。
var isPlayed = false;
var oldValue = myVariable;

if (myVariable >= 10 && myVariable <= 30 && !isPlayed) {
    sound.play("myFirstSound"); 
    isPlayed = false;
} 

需要时初始化变量... 根据你所说的,我猜你需要一个变量来比较循环中的值并将 isPlayed 标志设置为 false:

if (myVariable != oldValue)
    isPlayed = false;

我想补充一点,他必须为您的解决方案中的每个条件添加一个标志。只有在原帖想要在单个循环中播放除标记音频外的其他音频时才需要这样做。问题不是很清楚。 - Jared Teng
OP想在变量值改变时播放声音,但为了避免内存问题,只需要播放一次... 只需要一个标志就可以了... - Jordi Castilla
澄清一下。这个想法是每个条件只播放一个声音。howler.js被设计为提供尽可能多的节点。这就是为什么我可以播放几个相同声音的实例。 - ifthisthenthat

3

只需使用布尔变量即可。

var alreadyPlayed = false;

for(somecondition){
   if(alreadyPlayed) continue;

   sound.play("myFirstSound");
   alreadyPlayed = true;
}

你明白了吧。

1
布尔值是一个好主意。你还可以利用声音对象的onend属性,这样你就知道什么时候可以再次播放声音了。像这样:
var playing = false;
sound.onend = function () { playing = false;  };

while (condition) {
   if (!playing & ...)
       ...
   ...
}

1

看到你对问题的编辑,添加延迟到下一个触发器,指南针可能触发得太快了。虽然我不熟悉compass.js,但我可以看到它每度触发一次,这很多...如果你把手机倾斜180度,那就是180个触发器。 可以尝试使用以下方式:

setTimeout(function() { your_func(); }, 50); 

对于50毫秒的延迟

您还可以通过添加一个计数器来将可用触发器从360个限制为36个或更少,每个计数为1度。因此,只有在移动10度后才会触发。

$(function(){
var counter = 0;
Compass.watch(function (heading) {
   if(counter <=10){
     counter++;
    }
    else{ 
   counter = 0;
  $('.degrees').text(Math.floor(heading) + '°');
  $('#rotate').css('-webkit-transform', 'rotate(' + (-heading) + 'deg)');

   if (heading >= 10 && heading <= 30) {
   sound.play("myFirstSound"); 
   } 
   else if (heading >= 31 && heading <= 60) {
   sound.play("mySecondSound");
   } else { etc etc...
   }       
   });
});

我试过了,现在发生了很多奇怪的事情。指南针的每个功能都超时了10步。如果我将if逻辑放在指南针函数外面会怎样?这引出了另一个问题,即如何在指南针函数外读取heading变量?非常感谢您的关注。 - ifthisthenthat
什么奇怪的东西?我认为你不会真正实现任何东西。从你的代码来看,你似乎在每30度播放一次声音。尝试将计数器设置为30。抱歉,我不知道compass.js或手机上的指南针的行为。它是否触发每个度数的变化? - Jared Teng
标题变量在哪里声明的?为了快速测试,请在compass watch函数后面添加console.log(header);。尝试阅读闭包以了解嵌套函数中的变量作用域。 - Jared Teng
谢谢JaredT。标题变量似乎是插件的一部分,而不是在我的代码中声明的。我想它是在compass.js中声明的。插件似乎在不断寻找变化。这可以解释行为。我想到了另一个解决方案。既然我正在发送度数数字到HTML以便显示它,我也可以添加一个事件监听器来监视HTML元素的内容。这可能不太优雅,但如果能够奏效,我会很满意。 - ifthisthenthat
你只需要传递触发器。除非你限制触发器,否则它会快速触发。出了什么问题?我没有看到代码有任何问题,也许需要稍微修改一下,比如如果方向改变,立即播放声音。你尝试过使用计数器并将其设置为360/(你有多少个声音)吗? - Jared Teng
显示剩余2条评论

0

只需添加一小层抽象,以跟踪当前正在播放的内容。

var nameOfSoundPlaying = null;

function play(soundName) {
   if (nameOfSoundPlaying == soundName) { 
      return; 
   } else {
     if (nameOfSoundPlaying != null) {
        // stop currently playing sound (if still playing)
        ...
     }  
     nameOfSoundPlaying = soundName;
     sound.play(soundName);
   }
}

这将简化您的代码:

$(function(){

    Compass.watch(function (heading) {
      $('.degrees').text(Math.floor(heading) + '°');
      $('#rotate').css('-webkit-transform', 'rotate(' + (-heading) + 'deg)');

       if (heading >= 10 && heading <= 30) {
           play("myFirstSound"); 
       } 
       else if (heading >= 31 && heading <= 60) {
           play("mySecondSound");
       } else { etc etc...
       });
});

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