最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - setTimeout returns error with Uncaught TypeError: Illegal invocation in AudioContext in Chrome - Stack Overflow

programmeradmin2浏览0评论

In Chrome I first create a continuous tone with the AudioContext:

var audioCtx = new (window.AudioContext || window.webkitAudioContext);

var oscillator = audioCtx.createOscillator();
var gainNode = audioCtx.createGain();

oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);

oscillator.start();

Now I want to stop it after a few milliseconds. So I do this:

setTimeout(oscillator.stop, 500)

This returns the error Uncaught TypeError: Illegal invocation.

However if I do;

setTimeout(function(){oscillator.stop()}, 500)

it works fine.

I would like to now why the first one doesn't work and returns an error. It seems like the straightforward way to do this.

In Chrome I first create a continuous tone with the AudioContext:

var audioCtx = new (window.AudioContext || window.webkitAudioContext);

var oscillator = audioCtx.createOscillator();
var gainNode = audioCtx.createGain();

oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);

oscillator.start();

Now I want to stop it after a few milliseconds. So I do this:

setTimeout(oscillator.stop, 500)

This returns the error Uncaught TypeError: Illegal invocation.

However if I do;

setTimeout(function(){oscillator.stop()}, 500)

it works fine.

I would like to now why the first one doesn't work and returns an error. It seems like the straightforward way to do this.

Share Improve this question asked Apr 15, 2015 at 2:55 HoushalterHoushalter 2,8181 gold badge19 silver badges21 bronze badges 4
  • 1 setTimeout(oscillator.stop.bind(oscillator), 500) – elclanrs Commented Apr 15, 2015 at 2:59
  • Thanks, that works. But why does it work, and why doesn't the simple way work? – Houshalter Commented Apr 15, 2015 at 3:07
  • This doesn't really answer your question, but another way to achieve the same effect would be to call stop() directly with the number of seconds to wait as the parameter so in your case oscillator.stop(0.5). Here is a working fiddle – HJ05 Commented Apr 15, 2015 at 3:09
  • I tried that first actually but it seems to be buggy in Chrome. It seems to measure the time since AudioContext was created, rather than the time since it was called. E.g. this: jsfiddle/j3q3npkc – Houshalter Commented Apr 15, 2015 at 3:29
Add a ment  | 

1 Answer 1

Reset to default 9

Your original code doesn't work because the stop function is passed to setTimeout without any context - it does not know which object it is supposed to act on. If you invoke it like this:

oscillator.stop();

Then within stop, the special variable this is set to the object pointed to by oscillator. But if you refer to it like this:

var x = oscillator.stop;

The function is not actually invoked. Rather, a reference to the function is simply extracted from oscillator and stored elsewhere. The function does not remember where it came from, and could be stored in many different variables or object properties at the same time. For example:

var x = {};
x.foo = oscillator.stop;
x.foo();

The last line calls stop with a context of x (this is set to x) rather than oscillator. (The function's body will cause errors since stop makes assumptions about what its context looks like, but the call itself is legal.) Alternatively, if you do this:

var foo = oscillator.stop;
foo();

Then stop will be called with only a default context. In strict mode, this will be set to undefined, and in non-strict mode, this will be set to window.

When you do this:

setTimeout(function(){oscillator.stop()}, 500)

The anonymous function invokes stop with the proper context. If, as suggested by @elclanrs in ments, you do this:

setTimeout(oscillator.stop.bind(oscillator), 500)

It is effectively the same thing: an anonymous function is created that calls stop with a context of oscillator.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论