mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
132 lines
4.0 KiB
JavaScript
132 lines
4.0 KiB
JavaScript
'use strict';
|
|
|
|
var updatesScheduled = false;
|
|
var batchStack = []; // A stack of batched updates
|
|
var unbatchedQueue = []; // Used for scheduled batched updates
|
|
|
|
var win = window;
|
|
var setImmediate = win.setImmediate;
|
|
|
|
if (!setImmediate) {
|
|
if (win.postMessage) {
|
|
var queue = [];
|
|
var messageName = 'si';
|
|
win.addEventListener('message', function (event) {
|
|
var source = event.source;
|
|
if (source == win || !source && event.data === messageName) {
|
|
event.stopPropagation();
|
|
if (queue.length > 0) {
|
|
var fn = queue.shift();
|
|
fn();
|
|
}
|
|
}
|
|
}, true);
|
|
|
|
setImmediate = function(fn) {
|
|
queue.push(fn);
|
|
win.postMessage(messageName, '*');
|
|
};
|
|
} else {
|
|
setImmediate = setTimeout;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function is called when we schedule the update of "unbatched"
|
|
* updates to components.
|
|
*/
|
|
function updateUnbatchedComponents() {
|
|
if (unbatchedQueue.length) {
|
|
try {
|
|
updateComponents(unbatchedQueue);
|
|
} finally {
|
|
// Reset the flag now that this scheduled batch update
|
|
// is complete so that we can later schedule another
|
|
// batched update if needed
|
|
updatesScheduled = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
function scheduleUpdates() {
|
|
if (updatesScheduled) {
|
|
// We have already scheduled a batched update for the
|
|
// process.nextTick so nothing to do
|
|
return;
|
|
}
|
|
|
|
updatesScheduled = true;
|
|
|
|
setImmediate(updateUnbatchedComponents);
|
|
}
|
|
|
|
function updateComponents(queue) {
|
|
// Loop over the components in the queue and update them.
|
|
// NOTE: It is okay if the queue grows during the iteration
|
|
// since we will still get to them at the end
|
|
for (var i=0; i<queue.length; i++) {
|
|
var component = queue[i];
|
|
component.update(); // Do the actual component update
|
|
}
|
|
|
|
// Clear out the queue by setting the length to zero
|
|
queue.length = 0;
|
|
}
|
|
|
|
function batchUpdate(func) {
|
|
// If the batched update stack is empty then this
|
|
// is the outer batched update. After the outer
|
|
// batched update completes we invoke the "afterUpdate"
|
|
// event listeners.
|
|
var batch = {
|
|
$__queue: null
|
|
};
|
|
|
|
batchStack.push(batch);
|
|
|
|
try {
|
|
func();
|
|
} finally {
|
|
try {
|
|
// Update all of the components that where queued up
|
|
// in this batch (if any)
|
|
if (batch.$__queue) {
|
|
updateComponents(batch.$__queue);
|
|
}
|
|
} finally {
|
|
// Now that we have completed the update of all the components
|
|
// in this batch we need to remove it off the top of the stack
|
|
batchStack.length--;
|
|
}
|
|
}
|
|
}
|
|
|
|
function queueComponentUpdate(component) {
|
|
var batchStackLen = batchStack.length;
|
|
|
|
if (batchStackLen) {
|
|
// When a batch update is started we push a new batch on to a stack.
|
|
// If the stack has a non-zero length then we know that a batch has
|
|
// been started so we can just queue the component on the top batch. When
|
|
// the batch is ended this component will be updated.
|
|
var batch = batchStack[batchStackLen-1];
|
|
|
|
// We default the batch queue to null to avoid creating an Array instance
|
|
// unnecessarily. If it is null then we create a new Array, otherwise
|
|
// we push it onto the existing Array queue
|
|
if (batch.$__queue) {
|
|
batch.$__queue.push(component);
|
|
} else {
|
|
batch.$__queue = [component];
|
|
}
|
|
} else {
|
|
// We are not within a batched update. We need to schedule a batch update
|
|
// for the process.nextTick (if that hasn't been done already) and we will
|
|
// add the component to the unbatched queued
|
|
scheduleUpdates();
|
|
unbatchedQueue.push(component);
|
|
}
|
|
}
|
|
|
|
exports.$__queueComponentUpdate = queueComponentUpdate;
|
|
exports.$__batchUpdate = batchUpdate; |