最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - setTimeout(0) vs window.postMessage vs MessagePort.postMessage - Stack Overflow

programmeradmin0浏览0评论

Apparently, using window.postMessage is a preferred way to queue an async javascript callback over window.setTimeout(fn, 0) across all modern browsers. I could not find a similar parison between window.postMessage and MessagePort.postMessage (using the same MessageChannel for sending and receiving messages asynchronously). Has anyone seen or done any timing? Does MessagePort.postMessage work for this purpose at all (where available)?

[EDITED] MessagePort.postMessage does work for this, but window.postMessage remains a preffered way, IMO (see my answer).

Apparently, using window.postMessage is a preferred way to queue an async javascript callback over window.setTimeout(fn, 0) across all modern browsers. I could not find a similar parison between window.postMessage and MessagePort.postMessage (using the same MessageChannel for sending and receiving messages asynchronously). Has anyone seen or done any timing? Does MessagePort.postMessage work for this purpose at all (where available)?

[EDITED] MessagePort.postMessage does work for this, but window.postMessage remains a preffered way, IMO (see my answer).

Share Improve this question edited Sep 18, 2013 at 1:32 noseratio asked Sep 16, 2013 at 11:13 noserationoseratio 61.7k36 gold badges223 silver badges500 bronze badges 1
  • As this still gets views... check out queueMicrotask. – noseratio Commented Oct 20, 2021 at 0:13
Add a ment  | 

1 Answer 1

Reset to default 8

[UPDATE] Added a test for setImmediate and a JSFiddle. Related, there's a cross-browser implementation of setImmediate and ASAP library used by Q for a promise resolution/rejection.

I went ahead and did some timing, using a modified version of David Baron's code, the results are below:

setTimeoutMC - using MessageChannel
setTimeoutPM - using window.postMessage
setTimeout(0) - using setTimer

IE10:

2000 iterations of setTimeoutMC took 126 milliseconds.
2000 iterations of setTimeoutPM took 190 milliseconds.
2000 iterations of setTimeout(0) took 7986 milliseconds.

Chrome v29.0.1547.66:

2000 iterations of setTimeoutMC took 144 milliseconds.
2000 iterations of setTimeoutPM took 81 milliseconds.
2000 iterations of setTimeout(0) took 10589 milliseconds.

Clearly, window.postMessage is the winner here (considering the level of existing cross-browser support for it). The looser is window.setTimeout(fn, 0) and should be avoided wherever possible.

Code:

<!DOCTYPE html>
<html>
<head>
    <!-- http://stackoverflow./q/18826570/1768303 -->
    <!-- based on http://dbaron/log/20100309-faster-timeouts -->
    <!-- requires IE10 or Chrome. Firefox doesn't support MessageChannel yet -->
    <title></title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <script type="text/javascript">

        // setTimeoutMC via MessageChannel

        (function () {
            "use strict";
            var i = 0;
            var timeouts = {};
            var setApiName = "setTimeoutMC";
            var clearApiName = "clearTimeoutMC";

            var channel = new MessageChannel();

            function post(fn) {
                if (i === 0x100000000) // max queue size
                    i = 0;
                if (++i in timeouts)
                    throw new Error(setApiName + " queue overflow.");
                timeouts[i] = fn;
                channel.port2.postMessage(i);
                return i;
            }

            channel.port1.onmessage = function (ev) {
                var id = ev.data;
                var fn = timeouts[id];
                if (fn) {
                    delete timeouts[id];
                    fn();
                }
            }

            function clear(id) {
                delete timeouts[id];
            }

            channel.port1.start();
            channel.port2.start();

            window[setApiName] = post;
            window[clearApiName] = clear;
        })();

        // setTimeoutPM via window.postMessage

        (function () {
            "use strict";
            var i = 0;
            var timeouts = {};
            var setApiName = "setTimeoutPM";
            var clearApiName = "clearTimeoutPM";
            var messageName = setApiName + new Date().getTime();

            function post(fn) {
                if (i === 0x100000000) // max queue size
                    i = 0;
                if (++i in timeouts)
                    throw new Error(setApiName + " queue overflow.");
                timeouts[i] = fn;
                window.postMessage({ type: messageName, id: i }, "*");
                return i;
            }

            function receive(ev) {
                if (ev.source !== window)
                    return;
                var data = ev.data;
                if (data && data instanceof Object && data.type === messageName) {
                    ev.stopPropagation();
                    var id = ev.data.id;
                    var fn = timeouts[id];
                    if (fn) {
                        delete timeouts[id];
                        fn();
                    }
                }
            }

            function clear(id) {
                delete timeouts[id];
            }

            window.addEventListener("message", receive, true);
            window[setApiName] = post;
            window[clearApiName] = clear;
        })();

        // timing

        function runtest() {
            var output = document.getElementById("output");
            var outputText = document.createTextNode("");
            output.appendChild(outputText);
            function printOutput(line) {
                outputText.data += line + "\n";
            }

            var n = 2000;
            var i = 0;
            var startTime = Date.now();
            setTimeoutMC(testMC);

            function testMC() {
                if (++i === n) {
                    var endTime = Date.now();
                    printOutput(n + " iterations of setTimeoutMC took " + (endTime - startTime) + " milliseconds.");
                    i = 0;
                    startTime = Date.now();
                    setTimeoutPM(testPM, 0);
                } else {
                    setTimeoutMC(testMC);
                }
            }

            function testPM() {
                if (++i === n) {
                    var endTime = Date.now();
                    printOutput(n + " iterations of setTimeoutPM took " + (endTime - startTime) + " milliseconds.");
                    i = 0;
                    startTime = Date.now();
                    setTimeout(test, 0);
                } else {
                    setTimeoutPM(testPM);
                }
            }

            function test() {
                if (++i === n) {
                    var endTime = Date.now();
                    printOutput(n + " iterations of setTimeout(0) took " + (endTime - startTime) + " milliseconds.");
                }
                else {
                    setTimeout(test, 0);
                }
            }
        }
    </script>
</head>

<body onload="runtest()">
    <pre id="output"></pre>
</body>
</html>
发布评论

评论列表(0)

  1. 暂无评论