I have a file browser application I want to integrate into an iframe of a main website. To adjust the scroll height of the iframte to the content I use following code:
iframecontent:
window.top.postMessage({ height: document.body.scrollHeight }, "*");
main site html:
<iframe id="iframe1" src="https://mysubfilebrowser.com" frameborder="0" scrolling="no" width="100%" height="10000">
Your browser doesn't support iframes
</iframe>
<script>
let iframe = document.getElementById("iframe1");
window.addEventListener('message', function(e) {
let message = e.data;
iframe.style.height = message.height + 'px';
} , false);
</script>
This works as it should but I have problems with performance. If I click in file/folder tree to fast, the post message event seems to be fired so much, that the iframe suddenly do not show the correct content or even empty areas.
Any hints what I can do, to solve this problem?
Thanks in advance!
Best regards Mini25
It sounds like a "single" change makes that call run many times (the scroll
and resize
events can be like that, amongst others). To handle that, you can "debounce" your call to postMessage
so it only makes the call once when it gets a lot of triggers in a short period of time.
It's quite simple to do: don't do the call right away, wait up to (say) 10, 50, or 100ms before doing it, and if you get another trigger to do it, reset that delay. That means you won't actually do it until things have settled down.
Here's a simple ad hoc version just for that code, but a web search for "debounce" will turn up various general-purpose debouncing wrappers for functions:
let updateWindowDebounceTimer = 0;
function updateWindow() {
// If there's a pending previous call, cancel it
clearTimeout(updateWindowDebounceTimer);
// Schedule a call for 10ms from now
updateWindowDebounceTimer = setTimeout(sendUpdate, 100);
}
function sendUpdate() {
updateWindowDebounceTimer = 0;
window.top.postMessage({ height: document.body.scrollHeight }, "*");
}
Then use updateWindow();
where you're currently using window.top.postMessage(/*...*/)
.
Here's an example using the scroll
event without debouncing (notice how fast the counter goes up when you scroll):
function updateWindow() {
/*
window.top.postMessage({ height: document.body.scrollHeight }, "*");
*/
const display = document.getElementById("counter");
display.textContent = String(parseInt(display.textContent, 10) + 1);
}
window.addEventListener("scroll", updateWindow);
body {
padding-top: 0;
margin-top: 0;
}
#counter {
position: sticky;
top: 0;
}
.tall {
margin-top: 1em;
height: 10000px;
}
<div id="counter">0</div>
<div class="tall">Scroll over this div</div>
And here's an example with debouncing (notice how much more slowly the counter goes up, indicating fewer update calls):
let updateWindowDebounceTimer = 0;
function updateWindow() {
// If there's a pending previous call, cancel it
clearTimeout(updateWindowDebounceTimer);
// Schedule a call for 10ms from now
updateWindowDebounceTimer = setTimeout(sendUpdate, 50);
}
function sendUpdate() {
updateWindowDebounceTimer = 0;
/*
window.top.postMessage({ height: document.body.scrollHeight }, "*");
*/
const display = document.getElementById("counter");
display.textContent = String(parseInt(display.textContent, 10) + 1);
}
window.addEventListener("scroll", updateWindow);
body {
padding-top: 0;
margin-top: 0;
}
#counter {
position: sticky;
top: 0;
}
.tall {
margin-top: 1em;
height: 10000px;
}
<div id="counter">0</div>
<div class="tall">Scroll over this div</div>
That's an ad-hoc version, but a web search for "debounce" will turn up various general-purpose debouncing wrappers for functions.