aboutsummaryrefslogtreecommitdiff
path: root/node_modules/montage/core/next-tick.js
blob: 0c3e209a4d327762ffdac174ab41f5f70ad5ba6a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/* <copyright>
 This file contains proprietary software owned by Motorola Mobility, Inc.<br/>
 No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/>
 (c) Copyright 2011 Motorola Mobility, Inc.  All Rights Reserved.
 </copyright> */

/**
    Defines [nextTick()]{#link nextTick}
    @see nextTick
    @module montage/core/next-tick
*/

/**
    @function
    @name nextTick
*/

(function (definition) {
    if (typeof bootstrap !== "undefined") {
        bootstrap("core/next-tick", definition);
    } else if (typeof require !== "undefined") {
        definition(require, exports, module);
    } else {
        definition({}, {}, {});
    }
})(function (require, exports, module) {

var nextTick;
// Node implementation:
if (typeof process !== "undefined") {
    nextTick = process.nextTick;
// Browser implementation: based on MessageChannel, setImmediate, or setTimeout
} else {

    // queue of tasks implemented as a singly linked list with a head node
    var head = {}, tail = head;
    // whether a task is pending is represented by the existence of head.next

    nextTick = function (task) {
        var alreadyPending = head.next;
        tail = tail.next = {task: task};
        if (!alreadyPending) {
            // setImmediate,
            // postMessage, or
            // setTimeout:
            request(flush, 0);
        }
    }

    var flush = function () {
        try {
            // unroll all pending events
            while (head.next) {
                head = head.next;
                // guarantee consistent queue state
                // before task, because it may throw
                head.task(); // may throw
            }
        } finally {
            // if a task throws an exception and
            // there are more pending tasks, dispatch
            // another event
            if (head.next) {
                // setImmediate,
                // postMessage, or
                // setTimeout:
                request(flush, 0);
            }
        }
    };

    var request; // must always be called like request(flush, 0);
    // in order of desirability:
    if (typeof setImmediate !== "undefined") {
        request = setImmediate;
    } else if (typeof MessageChannel !== "undefined") {
        // http://www.nonblocking.io/2011/06/windownexttick.html
        var channel = new MessageChannel();
        channel.port1.onmessage = flush;
        request = function (flush, zero) {
            channel.port2.postMessage(0);
        };
    } else {
        request = setTimeout;
    }

}

exports.nextTick = nextTick;

});