我想requestAnimationFrame在 1 秒后停止:
rAF = requestAnimationFrame(draw);
所以我用setTimeout.
當我將其包裝cancelAnimationFrame(rAF)在箭頭函式中時,它可以正常作業:
setTimeout(() => cancelAnimationFrame(rAF), 1000);
但是,當我cancelAnimationFrame用作函式本身并rAF作為第三個引數傳遞給 時setTimeout,它不起作用:
setTimeout(cancelAnimationFrame, 1000, rAF);
我以為我一開始并不知道確切的語法setTimeout。但是,我認為語法沒有錯,因為這段代碼可以正常作業:
setTimeout(alert, 1000, "Hello");
為什么它不起作用?
uj5u.com熱心網友回復:
rAF不同之處在于評估的時間點。
解釋
據推測,您的代碼如下所示:
let rAF;
const draw = () => {
// Do some work.
rAF = requestAnimationFrame(draw);
};
rAF = requestAnimationFrame(draw);
當你這樣做時:
setTimeout(cancelAnimationFrame, 1000, rAF);
您將三個值傳遞給setTimeout:一個函式、一個數字和另一個數字。執行此陳述句時,會評估呼叫,這意味著首先將setTimeout識別符號決議為函式參考。其次,評估三個引數:cancelAnimationFrame識別符號被決議為函式參考,然后數字文字是數字原語,然后rAF識別符號被決議為另一個數字原語。然后,執行呼叫。
這就是所有setTimeout看到的。在 JavaScript 中,不能像在 C 中那樣傳遞對數字的參考。
讓我們假設rAF最初是1. 在一秒鐘的程序中,rAF被反復遞增并最終達到該值61左右。
由于您setTimeout在開始時注冊,因此宣告
setTimeout(cancelAnimationFrame, 1000, rAF);
相當于
setTimeout(cancelAnimationFrame, 1000, 1);
然而,宣告
setTimeout(() => cancelAnimationFrame(rAF), 1000);
不等于_
setTimeout(() => cancelAnimationFrame(1), 1000);
僅在呼叫函式體時才對其進行評估。這意味著,JS不會“窺探函式內部”并嘗試評估變數。該陳述句本質上意味著“呼叫某個函式,并使用其他函式和數字 1000 作為引數”。
When the one second is over and it’s time to cancel the animation frame, setTimeout executes its callback.
If the callback is () => cancelAnimationFrame(rAF), then it’s executed, so the function body is evaluated: cancelAnimationFrame(rAF) is equivalent to cancelAnimationFrame(61).
However, in the non-working case, cancelAnimationFrame stays the same, the argument 1 (equivalent to rAF at the time setTimeout was originally called) stays the same.
You can’t cancel frame 1 when you’re already at frame 61.
And setTimeout(alert, 1000, "Hello"); works, of course, because "Hello" is static, is only evaluated once, never changes.
Related
Here’s a more general situation where this behavior can be examined:
let greeting = "Hello";
const greet = (theGreeting) => console.log(`${theGreeting}, world!`);
const boundGreeting = greet.bind(null, greeting);
greeting = "Goodbye";
boundGreeting(); // Logs "Hello, world!".
greet(greeting); // Logs "Goodbye, world!".
bind passes the 2nd parameter (greeting) as the 1st argument to greet (ignore the null).
This is much like using setTimeout(greet, 0, greeting);, except this is unrelated to timeouts and we call (the bound) greet ourselves.
You could pass something like a reference, i.e. an object, to make it work, if you had a function that also accepts an object:
const timing = {
rAF: null
},
cancelTiming = ({ rAF }) => cancelAnimationFrame(rAF),
draw = () => {
// Do some work.
timing.rAF = requestAnimationFrame(draw);
};
timing.rAF = requestAnimationFrame(draw);
setTimeout(cancelTiming, 1000, timing);
This works because when passing timing, the value being passed is a reference.
Mutating it, e.g. by updating the rAF property, is visible everywhere where this reference is visible.
But this makes programming quite cumbersome.
This is tangentially related to Is JavaScript a pass-by-reference or pass-by-value language?.
Alternative
There’s an alternative to using setTimeout.
When requestAnimationFrame calls its callback function, it passes a DOMHighResTimeStamp, similar to what performance.now returns.
So you could make the check in your draw function:
const timeoutTimestamp = performance.now() 1000,
draw = (now) => {
// Do some work.
if(now < timeoutTimestamp){
requestAnimationFrame(draw);
}
};
requestAnimationFrame(draw);
Related: Stop requestAnimationFrame after a couple of seconds.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/434869.html
標籤:javascript 功能 变量 设置超时
上一篇:將串列元素一一作為函式的引數傳遞
