我昨天发布了this site(一个实时编辑网站three.js示例)并发现在更新代码或导航到多个示例文件时,帧速率猛增至1000 f / s左右
首先提到这一点是here。我不确定为什么更新后帧速率会增加。 WebGL画布在iframe中,我正在使用此代码更新iframe内容(iframe的id为'preview):
var previewFrame = document.getElementById('preview');
var preview = previewFrame.contentDocument || previewFrame.contentWindow.document;
preview.open();
preview.write(this.props.code);
preview.close();
有没有人知道如何解决这个问题?编辑工作使用CodeMirror完成,网站使用React构建。所有src代码都在repo here。
答案 0 :(得分:1)
我的猜测是你正在启动多个requestAnimationFrame循环。
例如
let numLoops = 0;
const countElem = document.querySelector("#count");
const stats = new Stats();
document.body.appendChild(stats.domElement);
function loop() {
stats.update();
requestAnimationFrame(loop);
}
function startLoop() {
++numLoops;
countElem.textContent = numLoops;
requestAnimationFrame(loop);
}
startLoop();
document.querySelector("button").addEventListener('click', startLoop);
<script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script>
<button>Click to add another requestAnimationFrame loop</button>
<div>Num Loops Running: <span id="count"></span></div>
我让我的示例可编辑然后在http://webglfundamentals.org上运行的方法是使用blob在iframe中运行示例。每当用户选择“更新”时,我都会使用他们编辑的源生成一个新blob,然后将iframe设置为该新blob的URL。这意味着示例完全重新加载,因此浏览器会丢弃任何旧的代码/循环/事件/ webgl上下文等。
您可以看到有效的the code here
function runLastVersionOfUsersCode() {
var url = getSourceBlob(usersEditedHtml);
someIFrameElement.src = url;
}
var blobUrl;
function getSourceBlob(options, htmlForIFrame) {
// if we already did this discard the old one otherwise
// it will stick around wasting memory
if (blobUrl) {
URL.revokeObjectURL(blobUrl);
}
var blob = new Blob([htmlForIFrame], {type: 'text/html'});
blobUrl = URL.createObjectURL(blob);
return blobUrl;
}
如果你看一下actual code for getSourceBlob
,你会发现它会做更多的工作,但基本上就是它。
答案 1 :(得分:0)
为了构建gman's有用的答案,我在React渲染循环(而不是threejs渲染循环)中使用了cancelAnimationFrame。提交在这里:https://github.com/ekatzenstein/three.js-live/commit/2cad65afa5fe066618a7aac179e096ee9e29ed76
//in the iframe
window.parent.three_live = requestAnimationFrame(animate)
//in the parent, on render loop
_resetAnimationFrame(){
//disables abnormally high frame rates
if(window.three_live){
var previewWindow = document.getElementById('preview').contentWindow;
previewWindow.cancelAnimationFrame(window.three_live);
}
}
执行window.parent是不必要的,但想在全局项目中引用。