代码如何检测是否在动画帧内运行

How can code detect if running inside an animation frame?

本文关键字:动画 运行 是否 何检测 检测 代码      更新时间:2023-09-26

如果某个函数被传递到requestAnimationFrame(),该函数如何检测到它在动画帧内被调用?

初版

function someFunction() {
  if (/* What goes here? */) {
    console.log('Inside animation frame.')
  }
  else {
    console.log('Not inside animation frame.')
  }
}
// The following lines should not be modified for the answer.
someFunction() // logs "Not inside animation frame."
requestAnimationFrame(someFunction) // eventually logs "Inside animation frame."

最后两行不能修改。我很想知道我是否可以检测到这种情况,而不需要用户记住以两种不同的方式使用该功能。最终用户应该像平常一样使用函数,而不知道我的函数检测用例。

目前不可能在Javascript中获得调用代码的上下文,因此除非更改requestAnimationFrame(),否则无法做您想做的事情,但谢天谢地,您可以这样做。试试这个…

// save a reference to the existing method and then override it...
window._requestAnimationFrame = window.requestAnimationFrame;
window.requestAnimationFrame = function(callback) {
	return window._requestAnimationFrame(function() {
		callback(true);
	});
}
function someFunction() {
	if (arguments.length && arguments[0]) {
		console.log('Inside animation frame.')
	}
	else {
		console.log('Not inside animation frame.')
	}
}
someFunction();
requestAnimationFrame(someFunction);

把我自己的答案放在这里供参考(感谢@phuzi, @Archer和@spender):

// save a reference to the existing method and then override it...
window.requestAnimationFrame = function (raf) { return function(callback) {
  return raf(function(time) {
    callback(time, true);
  });
}}(window.requestAnimationFrame.bind(window))
function someFunction(time, inFrame = false) {
  if (inFrame) {
    console.log('Inside animation frame.')
  }
  else {
    console.log('Not inside animation frame.')
  }
}
someFunction(); // logs "Not inside animation frame."
someFunction(63245); // still logs "Not inside animation frame."
requestAnimationFrame(someFunction); // eventually logs "Inside animation frame."

您可以将传递给requestAnimationFrame的函数bind

function someFunction(isInsideAnimationFrame, domHighResTimestamp) {
  if (isInsideAnimationFrame) {
    console.log('Inside animation frame.')
  }
  else {
    console.log('Not inside animation frame.')
  }
}
someFunction() // logs "Not inside animation frame."
requestAnimationFrame(someFunction.bind(null, true)) // eventually logs "Inside animation frame."

请参阅Function.prototype.bind了解其工作原理。

在文档中查找窗口。requestAnimationFrame回调,即someFunction将与DOMHighResTimeStamp一起被调用。

someFunction可以用

检测到
function someFunction(domHighResTimestamp) {
  if (domHighResTimestamp) {
    console.log('Inside animation frame.')
  }
  else {
    console.log('Not inside animation frame.')
  }
}

不幸的是,不能保证使用someFunction的人不会调用它传递值

你可以这样做:

导出getIsDuringAnimationFrame并对原生requestAnimationFrame功能进行补丁。

let animationFrameCallbacksCount = 0;
const originalRequestAnimationFrame = window.requestAnimationFrame.bind(window);
window.requestAnimationFrame = function requestAnimationFrame(callback: (time: number) => void) {
  return originalRequestAnimationFrame((time) => {
    try {
      animationFrameCallbacksCount++;
      callback(time);
    } finally {
      animationFrameCallbacksCount--;
    }
  })
}
export function getIsDuringAnimationFrame() {
  return animationFrameCallbacksCount > 0;
}