将参数传递给setTimeout:一个方法不起作用(JS)

时间:2017-06-12 01:37:36

标签: javascript arguments

我正在研究如何将参数传递给setTimeout(如建议的here。) 在while循环的上下文中激活HTML5 Audio元素。

这有效:

window.setTimeout(playTone, time, phrasePitches[x]);

奇怪的是,这不起作用:

window.setTimeout(function(){
    playTone(phrasePitches[x]);
}, time);

在控制台中,超时按计划进行,每次都显示:

  

TypeError:无法设置属性' currentTime'为null

所以出于某种原因,第二种方法不想接受数组...任何想法在这里发生了什么?

编辑...完整代码:

function playTone(tone){
        var tone = document.getElementById(tone);
        tone.currentTime = 0;
        tone.play();
    };

var pitchSet = new Array ("C3","D3","E3","F3","G3","A3","B3","C4");

fyshuffle (pitchSet);  // The Fischer-Yater shuffle function
    var i = 0;
    var phrasePitches = new Array();
    while (i < 4) { 
        phrasePitches.push(pitchSet[i]);
        i++; 
    }

var x=0;
var time = 0;
while(x<4){
//  window.setTimeout(playTone, time, phrasePitches[x]);  // This works.
    window.setTimeout(function(){
        playTone(phrasePitches[x]);
    }, time);
    time += 2000;
    x++;        
}

1 个答案:

答案 0 :(得分:1)

Audiosprites

此演示使用audiosprite⁰。我使用Audacity程序将小型MP3文件连接成一个更大的MP3文件✲。然后我以秒为单位记录了每个片段的开始和结束时间。如果手动方式看起来很艰难,那就有other ways to generate an audiosprite

✲我在创建audiosprite之后找到MergeMP3,所以我还没有测试过它,但它看起来比Audacity容易得多。

详细信息在演示文稿和与参考文献相对应的注释中进行了评论

演示

// Reference the <audio>
var fx = document.querySelector('#fx');

/* Reference the <fieldset> (can be any element with an
|| endtag: <tag></tag>
*/
var panel = document.querySelector('#panel');

/* Map the audiosprite's frags in an object of arrays 
|| Each array represents a frag which consists of: 
|| 'key': [start time, end time]¹
|| TODO: replace object literal with ES6 Map²
*/
var sprite = {
  'all': [0, 27],
  'click': [0, .45],
  'bell': [.65, 7.4],
  'elevator': [7.5, 9.7],
  'sonar': [10, 27]
};

// Declare default value of end time
var end = 0;

// Register the <audio> on the loadeddata event³...
fx.addEventListener('loadeddata', function(e) {

  /* Object.keys chained to .forEach()⁴ iterates through
  || 'sprite' properties (key/value pairs).
  */
  Object.keys(sprite).forEach(function(key, index) {

    /* On each iteration, generate a <button> inside the
    || <fieldset>
    || Note the use of a template literal⁵
    || TODO: Delegate⁶ click events to panel to avoid
    || inline attribute event handlers 
    */
    panel.innerHTML += `<button onclick="effect('${key}')">${key}</button>`;
  });
}, false);

// Register the <audio> on timeupdate event⁷...
fx.addEventListener('timeupdate', function(e) {

  /* timeupdate occurs when playing position changes
  || check if the currentTime⁸ property of <audio> 
  || is more than the value of 'end' 
  || ('end' is the second value of a frag: sprite[key][1])
  || If it is, pause the <audio>
  */
  if (fx.currentTime > end) {
    fx.pause();
  }
}, false);

/* This function passes the string value of 'key' 
|| in sprite object
|| Each 'key' has a value of an array containing an start
|| time and an end time. 
|| In short, 'key' is a reference to a frag.
*/
function effect(key) {

  // if the 'key' in 'sprite' object exists...
  if (sprite[key]) {

    /* The currentTime of <audio> is 
    || the first value of 'key' 
    */
    fx.currentTime = sprite[key][0];

    // Assign 'end' the second value of 'key' 
    end = sprite[key][1];

    /* Play <audio>
 	  || Note at this point, if done conventionally by
    || reloading the .src for each change to a separate
    || frag, fx.load() would need to be invoked
	  || as well, thereby incurring another HTTP request
	  */
    fx.play();
  }
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1, user-scalable=no">
  <style>

  </style>
</head>

<body>
  <section>
    <!-- 
An audiosprite⁰ is an audio file that is actually a
concatenation of multiple sound files 
(from now on refered to as frags) played at 
different times throughout its duration. 

The advantages are that:
- the file is downloaded once then cached
- the src doesn't change thus only one HTTP request needed

If done the conventional way with multiple frags there 
would be:
- several downloads for smaller files 
- the added HTTP request everytime the src attribute changes
  its url
-->
    <audio id='fx' src='http://vocaroo.com/media_command.php?media=s0L5VMshEG3E&command=download_mp3' controls></audio>
    <fieldset id='panel'>
      <legend>Effects</legend>
    </fieldset>
  </section>
  <!-- 
If using JS on the same page rather than externally,
place the JS here within a <script> block:
<script>
...:::JS code here:::...
</script>
-->

</body>

</html>

<小时/>

参考

audiosprite

¹key/value pairs

²ES6 Map ✎

³loadeddata event

Object.keys().forEach()

template literal

Event Delegation ✎

timeupdate event

currentTime

✎作为TODO提到,它在本演示中尚未实现。