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

Function Optimization

While this could also be considered a general JS question more suited to StackOverflow, I decided since it relies on functions available exclusively in Roll20 I should try here first. I have a code snippet that I'm trying to optimize. The goal is to grab all tokens that meet the following critiera: The token must be controlled by the player submitting the command OR the player submitting the command must be the GM. The token must be on the current page. The token must represent a character (no drawings). The token must be on the same layer that the player submitting the command is viewing. Not quite sure how to implement this. If it's not possible, then just limit it to the token layer for non-GMs and the token & GM layers for the GM. For most players, this will return 1 token, or a small number of tokens for players using characters with "pets". However, when used by the GM, this should return all NPC and PC tokens on the layer(s). I think my statements above restricts the list appropriately. My current code is: var allPlayerTokensOnPage = _.filter(findObjs({ type: 'graphic', _pageid: Campaign().get('playerpageid') }),function(filterItem){ return ( (_.contains(filterItem.get('controlledby'),command.playerid) && filterItem.get('layer') == 'objects') || (playerIsGM(command.playerid) && _.contains(['objects','gmlayer'],filterItem.get('layer'))) ) && filterItem.get('represents'); }); I'm not sure how well JS handles || operators when it comes to optimization. I know it's a nightmare in most DBMSs, and suboptimal in C#. The idea here is that if I have a page with a lot of graphics on it, I want to iterate through the list as few times as possible, and keep as many things out of the list as possible before I iterate through the list.
1432049396
The Aaron
Pro
API Scripter
filterObjs() will be just slightly faster than _.filter(findObjs()) , I had a discussion with Riley about it a while back. || and && both short-circuit in javascript, so ordering your conditionals for fastest failure will be slightly more efficient. Players are only "on" the objects layer. Use === and !== instead of == and != . == and != will do type conversions (which take some small amount of time and are unlikely to be what you want anyway). You probably mean to have filterItem.get('controlledby').split(/,/) .
I do wish there was something more specific for filtering objects by including at least the _type or _subtype category along with page location. That would speed up more intensive operations. <rant> A bit off topic, but the callback heuristic for getting access to the gmnotes/bio makes it a bit frustrating to work with given the lack of data storage mediums. Managing Async operations that rely on completion of work done in these callbacks in a known order requires semaphores upon semaphores. What used to be a fun little thing I'd do after-hours has become quite taxing as it's less javascript and more figuring out why certain bugs exist in the sandbox interface. Things like delete() not behaving well with a possible race condition existing for long running operations. Or callback routines for bio/gmnotes double executing during first use (upon sandbox start). Then again, I'm using these for more complex operations as opposed to 'roll my dice and do something simple' which is probably just me. </rant>
So fastest failure can change depending on whether or not you're the GM. Here's is what I've got based on your notes. I know the absolute fastest method could vary based on the number of graphics per page, the number of graphics per layer across all pages, and the number of pages. var allPlayerTokensOnPage = filterObjs(function(filterItem){ if(playerIsGM(command.playerid){ return filterItem.get('_pageid') === Campaign().get('playerpageid') && (filterItem.get('layer') === 'objects' || filterItem.get('layer') === 'gmlayer') && filteritem.get('represents'); } else { return filterItem.get('controlledby').indexOf(command.playerid) !== -1 && fitlerItem.get('_pageid') === Campaign().get('playerpageid') && filterItem.get('represents') && filterItem.get('layer') === 'objects'; } });
1432051952

Edited 1432053588
The Aaron
Pro
API Scripter
That looks pretty good to me. You can (possibly should?) leave the _ off the front of the read only properties you grab via .get('') . Sometimes read-only becomes read-write and you'll be ready that way. You still have to include them for the prev objects and for on() registrations.
Sweet. Thanks a ton for your help. @Ken: I've run into all of those issues as well. My biggest issue I just encountered last weekend when I spent all testing and debugging my scripts, only to have everything explode in a confusing mess at the end of the day all because server load increased and a function that I thought was synchronous turned out to be an async operation that created a race condition when the server load increased in the evening. Fortunately, there's always help in the forums. :D
1432053598
The Aaron
Pro
API Scripter
No problem!