【问题标题】:How can code detect if running inside an animation frame?代码如何检测是否在动画帧内运行?
【发布时间】:2017-03-17 06:50:57
【问题描述】:

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

f.e.

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."

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

【问题讨论】:

  • 你总是可以从调用站点传递一些东西:requestAnimationFrame(function(){someFunction(true)}) vs someFunction(false)
  • 确实如此,但如果我的功能交给其他人使用,不保证他们会这样做。或者,其他人甚至可能不知道他们正在间接调用此函数。
  • ES6 默认参数可能会有所帮助:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • @spender 这可能是迄今为止最好的答案,但仍不能确定 100%。例如,如果我们定义function someFunction(time = false) {},那么time 将在帧内时为时间戳,false 在帧外(除非用户为时间戳传递手动值)。

标签: javascript requestanimationframe


【解决方案1】:

目前无法在 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);

【讨论】:

  • 很可能 OP 无论如何都需要一个 polyfill,所以添加起来很简单。
  • 有点矫枉过正 - 如果在动画帧的上下文中调用回调,将使用单个参数 DOMHighResTimeStamp 调用。
  • 好主意。但有趣的是,在您的特定示例中,它仍然可以在没有猴子补丁的情况下工作。
  • phuzi 打败了我:是的,因为时间戳。
  • 谢谢,polyfill 的想法(虽然侵入性,我想它工作)。请参阅我自己的答案以供参考。
【解决方案2】:

将我自己的答案放在这里以供参考(感谢@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."

【讨论】:

    【解决方案3】:

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

    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

    更新

    查看window.requestAnimationFrame 的文档,回调即someFunction 将使用DOMHighResTimeStamp 调用。

    someFunction 可以检测到这一点

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

    不幸的是,无法保证使用someFunction 的人不会称其为传递值。

    【讨论】:

    • 嗨 phuzi,类似于spender 的cmets,我的函数的用户可能会也可能不会这样做。如果严格来说是我自己的代码,那么是的,那很容易。我会更新问题。
    • 更新了我的问题:示例中的最后两行不应修改。
    • 用替代方法更新了我的答案。我不确定是否有 100% 万无一失的方法来检测您想要的内容。
    • 接受了你的答案,但把我的作为参考,同样基于@Archer 的 polyfill 想法。
    • @trusktr 如果您的答案满足您的需求,请改为接受。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-08
    • 2015-12-24
    • 1970-01-01
    • 1970-01-01
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多