Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Sequential Semaphore Callback Arguments

So, using the semaphore code presented in the  API Cookbook , I am trying to enforce sequential callback arguments. var lock = new Semaphore(function(arg1, arg2, arg3){ log(arg1); log(arg2); log(arg3); }, 3); lock.p("fizz", 3); lock.p("foo", 1); lock.p("bar", 2); => "Foo", "Bar", "Fizz" Any help would be appreciated.  I've been working on this aspect for a bit while also debugging other portions of the code. The specific use case for this is that I am reading html tables out of multiple handouts, and the "lock.p()" call is in the callback for the handout notes, right after the table is parsed into JSON.  So each parameter in the semaphore callback needs to be tied to a specific handout, preferably without using multiple semaphores.
1445743125
The Aaron
Pro
API Scripter
Brian wrote that semaphore and you can certainly use it.  However, if I were doing it, I'd go a slightly different route. You can use the  _.after() function to build a function that will only execute after it has been called a set number of times.  So here is sample code that loads all the handouts, makes a function that expects to be called as many times as the number of handouts, then gets the notes section for all of them and in the callback calls _.after'd function: on('ready',function(){     'use strict';     var data = {},     handouts = findObjs( {type:'handout'}),     finallyUseHandoutData = _.after (handouts.length, function(){         _.each(data,function(d,id){             log( id+' :: '+_.first(d.split(/\s+/),10).join(' '));         });     });     _.each(handouts, function(h){         h.get('notes',function(notes){             data[h.id] = notes;             finallyUseHandoutData ();         });     }); }); That practical upshot is that in the callback, I store away the data I want (the notes value, which I put in an object keyed by the handout's id, then call the function, on the Nth time, the code in the function is actually executed.  It doesn't matter what order the callbacks for the .get() are called in, it will only execute when it has done all of them.  Then it will iterate all of them and spit out the id plus the first 10 words. If instead you want to do them in some numbered order, you can use the index for them in the handouts array instead: on('ready',function(){     'use strict';     var data = [],     handouts = findObjs( {type:'handout'}),     finallyUseHandoutData = _.after (handouts.length, function(){         _.each(data,function(d,i){             log( i+' :: '+_.first(d.split(/\s+/),10).join(' '));         });     });     _.each(handouts, function(h,i){         h.get('notes',function(notes){             data[i] = notes;             finallyUseHandoutData ();         });     }); }); Hope that helps!
1445744076
Lithl
Pro
Sheet Author
API Scripter
You can't force asynchronous operations to run sequentially. A semaphore is guaranteed to be able to let you know when they're all done, but it won't force them to complete in a specific order. Your only two approaches are to either not even start  the next asynchronous process until the previous one has completed (essentially making the necessarily-slow async operation an even slower synchronous one), or else do as Aaron has suggested and record the information you need in an ordered data structure with your async operation, and then process that data structure after all of the async operations have completed.
Alright, I think I've got it. General.GetJSONArrayFromTableHandout = function (handoutName, afterCallback, callbackArray) {     var handout = findObjs({ type: 'handout', name: handoutName })[0];     if (handout) {         handout.get('notes', function (notes) {             callbackArray.push(General.TableToJSONArray(notes, handoutName));             afterCallback();         });     } } General.TableToJSONArray = function(html, title) { var table = html; table = table.replace('<table>', '').replace('</table>', '').replace('<thead>', '').replace('</thead>', '').replace('<tbody>', '').replace('</tbody>', ''); var headers = []; var items = table.split('</tr>'); var output = { data: [], Name: title }; var headerRow = 1; _.each(items, function (item) { if (item != '') { var index = 0; item = item.replace('<tr>', ''); var jsonString = '{ '; var values = item.split('</td><td>'); _.each(values, function (value) { value = value.replace('<td>', ''); value = value.replace('</td>', ''); if (headerRow == 1) {    headers.push(value.replace( new RegExp(' ','g'),'_')); } else { if (index > 0) { jsonString = jsonString + ', '; } jsonString = jsonString + '"' + headers[index] + '" : "' + value + '"'; } index = index + 1; }); jsonString = jsonString + ' }'; if (headerRow != 1) { output.data.push(JSON.parse(jsonString)); } } headerRow = 0; }); return output; }; characterSheet.CalculateAbilityDerivedValues = function (characterId) { var abilityTables = [];     var callback = _.after(8, function () { /* Do work here */ });     General.GetJSONArrayFromTableHandout('Intelligence', callback, abilityTables);     General.GetJSONArrayFromTableHandout('Wisdom', callback, abilityTables);     General.GetJSONArrayFromTableHandout('Charisma', callback, abilityTables);     General.GetJSONArrayFromTableHandout('Strength', callback, abilityTables);     General.GetJSONArrayFromTableHandout('Dexterity', callback, abilityTables);     General.GetJSONArrayFromTableHandout('Constitution', callback, abilityTables);     General.GetJSONArrayFromTableHandout('Comeliness', callback, abilityTables);     General.GetJSONArrayFromTableHandout('Speed', callback, abilityTables); } My implementation here might be a little dirty, but I'm spoiled by the .NET library at work, so parsing HTML tables into JSON isn't really my strong suit.
1445750102
The Aaron
Pro
API Scripter
Glad you got it working!
Is it better to keep the handouts in memory or to read the information out of the handout every time?  I have about 25 handout tables I'm using.
1445756150
The Aaron
Pro
API Scripter
Wouldn't be an issue either way, but I'd tend toward caching the parsed data. 
Thanks for your help. :D