I think I've got it figured out now.. My solution is to async build up a flat list of items (from the recursive object) to process first, then do another async loop (which I'll build soon) to do the work per item, and when that's done, replace the placeholder with the result. This code works on a custom datastructure that looks like this; { hmData : { mijnDataA : 'a', mijnDataB : 'b', mijnSubKeyA : { hmData : { mijnDataX : 'x' }, hmSettings : { // app-specifc values for the object with key 'mijnDataX' } } }, hmSettings : { // app-specific values for the object with keys 'mijnDataA', 'mijnDataB', and 'mijnSubKeyA' } } Then, the actual code to build up a flat work list of this recursive array, up to a certain level deep (levelsAtOnce) is; printNextLevel : function (pvCmd) { if ( typeof pvCmd.val == 'object' && typeof pvCmd.val.hmStats == 'object' && typeof pvCmd.val.hmData == 'object' ) { //if (pvCmd.keyValueName && pvCmd.keyValueName!='') pvCmd.val.hmStats.keyValueName=pvCmd.keyValueName; //bit of a hack, i agree. var td = typeof pvCmd.val.hmData; var d = pvCmd.val.hmData; } else { var td = typeof pvCmd.val; var d = pvCmd.val; }; rajmv.hms.tools.printNextLevel_scan (pvCmd, rajmv.hms.tools.printNextLevel_buildDatanodes); return { html : '<tr><td>Have Yet To Render This</td></tr>' }; }, printNextLevel_scan : function (pvCmd, callback) { if (!pvCmd.scanResults) { pvCmd.scanResults = [{level:1, datanode:pvCmd.scanPointer}]; pvCmd.scanIdx = 0; pvCmd.scanCount = 0; pvCmd.lastPause = 0; pvCmd.scanCallback = callback; } rajmv.hms.tools.printNextLevel_scanItem (pvCmd); pvCmd.scanCount++; //rajmv.log (2, 'pvCmd.scanIdx='+pvCmd.scanIdx+', scanResults.length-1='+(pvCmd.scanResults.length-1)); if (pvCmd.scanIdx==pvCmd.scanResults.length-1) { if (typeof pvCmd.scanCallback=='function') { pvCmd.scanCallback (pvCmd); } return true; // scanning done! } var pauseFactor = pvCmd.scanCount / 7; if (pauseFactor > pvCmd.lastPause + 1) { setTimeout (function () { pvCmd.lastPause = pauseFactor; rajmv.hms.tools.printNextLevel_scan(pvCmd); }, 50); } else { rajmv.hms.tools.printNextLevel_scan(pvCmd); }; return false; // not done yet }, printNextLevel_scanItem : function (pvCmd) { var it = pvCmd.scanResults[pvCmd.scanIdx]; if (!it || !it.datanode) return false; var tit = typeof it.datanode; if (tit=='object' && it.datanode!==null && it.datanode!==undefined) { if (!it.keys && it.level<=pvCmd.levelsAtOnce) { it.keys = Object.keys (it.datanode); it.keyIdx = 0; } } if (it.keys) { if (it.keyIdx<it.keys.length) { var doUntil = it.keyIdx+20; while (it.keyIdx<doUntil && it.keyIdx<it.keys.length-1) { rajmv.hms.tools.printNextLevel_scanKey (pvCmd); it.keyIdx++; pvCmd.scanCount++; if (it.keyIdx==it.keys.length-1) { pvCmd.scanIdx++; pvCmd.scanCount++; } var pauseFactor = pvCmd.scanCount / 7; if (pauseFactor > pvCmd.lastPause + 1) break; } } } else { pvCmd.scanIdx++; pvCmd.scanCount++; } }, printNextLevel_scanKey : function (pvCmd) { var it = pvCmd.scanResults[pvCmd.scanIdx]; if (!it.keys[it.keyIdx]) debugger; pvCmd.scanResults.splice(pvCmd.scanIdx+1, 0, {level:it.level+1, datanode:it.datanode[it.keys[it.keyIdx]].hmData}); // insert next datanode just after the scanIdx rajmv.log (2, 'hms.tools.printNextLevel_scanKey(): pvCmd.scanCount='+pvCmd.scanCount); }, printNextLevel_buildDatanodes : function (pvCmd) { if (!pvCmd.html) pvCmd.html = ''; // this is where the flat list is ready to be processed (into HTML in my case); debugger; }, -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php