diff --git a/packages/moon/dist/moon.js b/packages/moon/dist/moon.js index a99bb2ab..0f53947f 100644 --- a/packages/moon/dist/moon.js +++ b/packages/moon/dist/moon.js @@ -550,7 +550,7 @@ /** * Global data */ - var data; + var data = {}; /** * Global views */ @@ -561,14 +561,6 @@ */ var components = {}; - /** - * Set data to a new object. - * @param {Object} dataNew - */ - - function setData(dataNew) { - data = dataNew; - } /** * Set old view to a new object. * @param {Object} viewOld @@ -600,10 +592,10 @@ var executeStart; /** - * Function scheduled to run in next frame + * Execution queue */ - var executeNextId = null; + var executeQueue = []; /** * Types of patches */ @@ -615,25 +607,6 @@ removeElement: 3, replaceElement: 4 }; - /** - * Schedules a function to run in the next frame. - * @param {Function} fn - */ - - function executeNext(fn) { - executeNextId = requestAnimationFrame(fn); - } - /** - * Cancels the function scheduled to run in the next frame. - */ - - - function executeCancel() { - if (executeNextId !== null) { - cancelAnimationFrame(executeNextId); - executeNextId = null; - } - } /** * Creates a DOM element from a view node. * @@ -641,7 +614,6 @@ * @returns {Object} node to be used as an old node */ - function executeCreate(node) { var nodeType = node.type; var nodeName = node.name; @@ -737,7 +709,7 @@ } else if (performance.now() - executeStart >= 8) { // If the current frame doesn't have sufficient time left to keep // running then continue executing the view in the next frame. - executeNext(function () { + requestAnimationFrame(function () { executeStart = performance.now(); executeView(nodes, parents, indexes); }); @@ -842,7 +814,7 @@ } else if (performance.now() - executeStart >= 8) { // If the current frame doesn't have sufficient time left to keep // running then continue diffing in the next frame. - executeNext(function () { + requestAnimationFrame(function () { executeStart = performance.now(); executeDiff(nodesOld, nodesNew, patches); }); @@ -916,7 +888,7 @@ _nodeParent.data.children.pop(); - _nodeParent.node.removeChild(patch.nodeOld); + _nodeParent.node.removeChild(patch.nodeOld.node); break; } @@ -943,8 +915,33 @@ break; } } + } // Remove the current execution from the queue. + + + executeQueue.shift(); // If there is new data in the execution queue, continue to it. + + if (executeQueue.length !== 0) { + executeNext(); } } + /** + * Execute the next update in the execution queue. + */ + + + function executeNext() { + // Get the next data update. + var dataNew = executeQueue[0]; // Record the current time to reference when running different functions. + + executeStart = performance.now(); // Merge new data into current data. + + for (var key in dataNew) { + data[key] = dataNew[key]; + } // Begin executing the view. + + + executeView([viewCurrent(data)], [null], [0]); + } /** * Executor * @@ -968,41 +965,20 @@ * are all batched together to update the view. Rather than doing it along with * the diff phase, the patch is done in one frame to prevent an inconsistent * UI -- similar to screen tearing. - */ - - - function execute() { - // Cancel any function scheduled to run in the next frame. - executeCancel(); // Record the current time to reference when running different functions. - - executeStart = performance.now(); // Begin executing the view. - - executeView([viewCurrent(data)], [null], [0]); - } - - /** - * Tracks if an execution is queued. - */ - - var queued = false; - /** - * Updates the global data and view. + * * @param {Object} dataNew */ - function set(dataNew) { - for (var key in dataNew) { - data[key] = dataNew[key]; - } - if (queued === false) { - queued = true; - setTimeout(function () { - execute(); - queued = false; - }, 0); + function execute(dataNew) { + // Push the new data to the execution queue. + executeQueue.push(dataNew); // Execute the next function in the queue if none are scheduled yet. + + if (executeQueue.length === 1) { + executeNext(); } } + /** * Moon * @@ -1030,7 +1006,6 @@ * @param {Object|string} options.view */ - function Moon(options) { // Handle the optional `name` parameter. var name = defaultValue(options.name, "Root"); @@ -1066,8 +1041,7 @@ node: root }); setViewCurrent(view); - setData(options); - execute(); + execute(options); } } Moon.lex = lex; @@ -1075,7 +1049,7 @@ Moon.generate = generate; Moon.compile = compile; Moon.components = components; - Moon.set = set; + Moon.set = execute; return Moon; })); diff --git a/packages/moon/dist/moon.min.js b/packages/moon/dist/moon.min.js index 5e582029..15e812dc 100644 --- a/packages/moon/dist/moon.min.js +++ b/packages/moon/dist/moon.min.js @@ -4,4 +4,4 @@ * Released under the MIT License * https://kbrsh.github.io/moon */ -!function(e,n){"undefined"==typeof module?e.Moon=n():module.exports=n()}(this,function(){"use strict";var v={element:0,text:1,component:2};var a,u,p,o,N=/<([\w\d-_]+)([^>]*?)(\/?)>/g,k=/\s*([\w\d-_:@]*)(?:=(?:("[^"]*"|'[^']*')|{([^{}]*)}))?/g;function n(e){e=e.trim();for(var n=[],t=0;t",t+2),i=e.slice(t+2,o);0,n.push({type:"tagClose",value:i}),t=o+1;continue}if("!"===a&&"-"===e[t+2]&&"-"===e[t+3]){var l=e.indexOf("--\x3e",t+4);0,t=l+3;continue}N.lastIndex=t;var d=N.exec(e);0;for(var u=d[0],p=d[1],f=d[2],c=d[3],s={},v=void 0;null!==(v=k.exec(f));){var h=v[0],m=v[1],g=v[2],y=v[3];0===h.length?k.lastIndex+=1:s[m]=void 0===y?g:y}n.push({type:"tagOpen",value:p,attributes:s,closed:"/"===c}),t+=u.length}else if("{"===r){var w="";for(t+=1;t]*?)(\/?)>/g,k=/\s*([\w\d-_:@]*)(?:=(?:("[^"]*"|'[^']*')|{([^{}]*)}))?/g;function t(e){e=e.trim();for(var t=[],n=0;n",n+2),d=e.slice(n+2,o);0,t.push({type:"tagClose",value:d}),n=o+1;continue}if("!"===a&&"-"===e[n+2]&&"-"===e[n+3]){var i=e.indexOf("--\x3e",n+4);0,n=i+3;continue}N.lastIndex=n;var l=N.exec(e);0;for(var u=l[0],p=l[1],s=l[2],f=l[3],c={},v=void 0;null!==(v=k.exec(s));){var h=v[0],m=v[1],g=v[2],y=v[3];0===h.length?k.lastIndex+=1:c[m]=void 0===y?g:y}t.push({type:"tagOpen",value:p,attributes:c,closed:"/"===f}),n+=u.length}else if("{"===r){var w="";for(n+=1;n= 8) { // If the current frame doesn't have sufficient time left to keep // running then continue executing the view in the next frame. - executeNext(() => { + requestAnimationFrame(() => { executeStart = performance.now(); + executeView(nodes, parents, indexes); }); @@ -255,8 +238,9 @@ function executeDiff(nodesOld, nodesNew, patches) { } else if (performance.now() - executeStart >= 8) { // If the current frame doesn't have sufficient time left to keep // running then continue diffing in the next frame. - executeNext(() => { + requestAnimationFrame(() => { executeStart = performance.now(); + executeDiff(nodesOld, nodesNew, patches); }); @@ -330,7 +314,7 @@ function executePatch(patches) { // efficient than removing at a specific index, especially because // they are equivalent in this case. nodeParent.data.children.pop(); - nodeParent.node.removeChild(patch.nodeOld); + nodeParent.node.removeChild(patch.nodeOld.node); break; } @@ -357,6 +341,33 @@ function executePatch(patches) { } } } + + // Remove the current execution from the queue. + executeQueue.shift(); + + // If there is new data in the execution queue, continue to it. + if (executeQueue.length !== 0) { + executeNext(); + } +} + +/** + * Execute the next update in the execution queue. + */ +function executeNext() { + // Get the next data update. + const dataNew = executeQueue[0]; + + // Record the current time to reference when running different functions. + executeStart = performance.now(); + + // Merge new data into current data. + for (let key in dataNew) { + data[key] = dataNew[key]; + } + + // Begin executing the view. + executeView([viewCurrent(data)], [null], [0]); } /** @@ -382,14 +393,15 @@ function executePatch(patches) { * are all batched together to update the view. Rather than doing it along with * the diff phase, the patch is done in one frame to prevent an inconsistent * UI -- similar to screen tearing. + * + * @param {Object} dataNew */ -export function execute() { - // Cancel any function scheduled to run in the next frame. - executeCancel(); - - // Record the current time to reference when running different functions. - executeStart = performance.now(); +export function execute(dataNew) { + // Push the new data to the execution queue. + executeQueue.push(dataNew); - // Begin executing the view. - executeView([viewCurrent(data)], [null], [0]); + // Execute the next function in the queue if none are scheduled yet. + if (executeQueue.length === 1) { + executeNext(); + } } diff --git a/packages/moon/src/index.js b/packages/moon/src/index.js index 54ac5966..b36a1a7c 100644 --- a/packages/moon/src/index.js +++ b/packages/moon/src/index.js @@ -3,33 +3,9 @@ import { parse } from "./compiler/parser/parser"; import { generate } from "./compiler/generator/generator"; import { compile } from "./compiler/compiler"; import { execute } from "./executor/executor"; -import { components, data, setData, setViewCurrent, setViewOld } from "./util/globals"; +import { components, setViewCurrent, setViewOld } from "./util/globals"; import { defaultObject, defaultValue, error, types } from "./util/util"; -/** - * Tracks if an execution is queued. - */ -let queued = false; - -/** - * Updates the global data and view. - * @param {Object} dataNew - */ -function set(dataNew) { - for (let key in dataNew) { - data[key] = dataNew[key]; - } - - if (queued === false) { - queued = true; - - setTimeout(() => { - execute(); - queued = false; - }, 0); - } -} - /** * Moon * @@ -94,8 +70,7 @@ export default function Moon(options) { node: root }); setViewCurrent(view); - setData(options); - execute(); + execute(options); } } @@ -104,4 +79,4 @@ Moon.parse = parse; Moon.generate = generate; Moon.compile = compile; Moon.components = components; -Moon.set = set; +Moon.set = execute; diff --git a/packages/moon/src/util/globals.js b/packages/moon/src/util/globals.js index e0c83814..dd282201 100644 --- a/packages/moon/src/util/globals.js +++ b/packages/moon/src/util/globals.js @@ -1,7 +1,7 @@ /** * Global data */ -export let data; +export const data = {}; /** * Global views @@ -13,14 +13,6 @@ export let viewOld, viewNew, viewCurrent; */ export const components = {}; -/** - * Set data to a new object. - * @param {Object} dataNew - */ -export function setData(dataNew) { - data = dataNew; -} - /** * Set old view to a new object. * @param {Object} viewOld