How to trace function calls in Marionette - javascript

Somewhere in the global scope:
let App = Backbone.Marionette.Application.extend({});
window.Ext = new App();
Inside Module A:
Ext.vent.trigger('Tracked:Email:send', {
from_email: tracking_data.sender,
to_emails: tracking_data.to,
cc_emails: tracking_data.cc,
email_id: tracking_data.email_id || '',
template: tracking_data.template_id || '',
subject: tracking_data.subject
});
Inside Module B:
Ext.vent.on('all', function (evt_name, params) {
// something else...
console.log(params);
}
The object's properties (from_email, to_emails & cc_emails) are undefined when I call console.log in Module B.
I've tried to debug this using console.trace, but the console doesn't show any functions that are involved in changing the object. I've also tried using Object.observe to capture the act of changing the object but no changes are detected.
Can some please teach me some debugging techniques to trace function calls and events in Marionette.
The scenario is:
our codebase is huge.
I'm a new guy at our company so I'm not sure if there are other functions or events that are involved.
I'm the only front end developer right now.

The good news: there's nothing special about Marionette here. Everyday JavaScript debugging techniques will help you out.
The bad news: as you're aware, debugging large, event-driven applications is difficult.
You could take these steps in Chrome dev tools (YMMV with other browsers):
Split the App.trigger line to get a reference to the parameters object:
let options = { from_email: ... }
App.vent.trigger('Tracked:Email:send', options);
Set a breakpoint on Ext.vent.trigger and run your code.
When execution pauses at the breakpoint, check that options contains the expected values. If not, the problem is somewhere before App.vent.trigger. Look up the call stack for any functions that affect tracking_data. You may need to check the Async checkbox if it is populated by asynchronous code.
If options contains the values you expect, carry on...
Whilst execution is paused use the console to save a global reference to your parameters object:
> OPTIONS = options
Add OPTIONS as a watch expression. Expand the item so you can watch changes to its properties.
Step through (including Marionette and Backbone code) until you see the OPTIONS properties change. If you don't see Marionette code when you step into App.vent.trigger you may need to remove Marionette from your black boxed libraries.

Related

When in the Chrome Debugger, is there anyway to reference data or functions inside an anonymous function block?

I'm trying to debug something live on a customer website and my code is all inside an anonymous function block. I don't know if there's anyway to reach that code to execute functions or look at variables in there. I can't put a breakpoint either because this code is dynamically generated each time the page is refreshed and the breakpoint doesn't stick.
(function() {
var Date = "14 September 2022 14:44:55"; // different every refresh for example
var Holder = {
var Items = {
item1: "Value1",
item2: "Value2"
};
function getItem(name) {
return Items[name];
};
function setItem(name, value) {
Items[name] = value;
};
setTimeout(DoSomething(), 2000);
})();
That's not the actual code, just a bare minimum example to illustrate the problem.
Is there anyway to get reach getItem() or Items?
Without a breakpoint that code probably runs to completion then POOF it's all gone anyway.
Redefine setTimeout
If it really is the case that the code inside the anonymous function calls other browser methods, you might be able to insert a detour at runtime that you can then put a breakpoint on.
For this to work, you will need to be able to inject new code into the page before the anonymous code, because there's no other way to invoke the IIFE.
Your example code uses setTimeout, so here's what I would try to insert:
let realSetTimeout = window.setTimeout
window.setTimeout = (...args) => {
debugger
return realSetTimeout(...args)
}
Lots of unrelated code might be calling setTimeout, in which case this could break the page or just make debugging really tedious. In that case, you might make it only debug if one of the setTimeout args has a value that's used in your example, e.g.:
// only break for our timeout
if(args[1] === 2000) debugger
Something like that might not trigger for only your code, but it would hugely reduce the number of other codepaths that get interrupted on their journey through the commonly-used browser capability.
Alternatively, use Charles Proxy to rewrite the body of the HTML page before it enters your browser. You could manually insert a debugger call directly into the anonymous function. Charles is not free, but I think they have a demo that might let you do this. If you do this professionally, it's probably a good purchase anyway. Your employer might even pay for the license.
If you can't use Charles (or a similar tool), you could instead set up a local proxy server using Node which does the rewrite for you. Something like that might only take an hour to throw together. But that is a bigger task, and deserves its own question if you need help with that.
No unfortunately.
The variables inside of the anonymous object are created in a scope which is inaccessible from the outside.
One of the main benefits of using a closure!
You’ll have to find a way to insert your own code inside of it by modifying the function that is generating those objects. If you can’t do that, then you’ll have to take the fork in the road and find another way.

SvelteJS vs ReactJS rendering difference (repaint / reflow)

Here's my naive understanding of how the DOM and browser works
Whenever something in the DOM ( the real dom ) changes the browser repaints or reflows that the DOM. So in simpler terms every time the DOM changes browser needs to recalculate the CSS, do a layout and repaint the web page. This is what takes time in real dom.
So React comes with this virtual DOM and what it actually does is it batches the changes and call applies them on real-dom in one go. Thus, minimizing the re-flow and re-paint.
Then what about Svelte. If it is manipulating the DOM directly how does it controls the repaint/reflow of the browser.
In addition to the (correct) answer above: Svelte "compiles" the code that you provide to it, so the final code can be executed without a library runtime (in contrast to React). And it creates rather readable code, so it is absolutely possible to understand the inner workings.
Note: This will be a bit longer answer - and still leave out many minute details about what is going on under the hood of Svelte. But I hope it helps to demystify some of the aspects what is going on under the hood. Also, this is how Svelte does things as of v3.16.x. Since this is internal, it might change. However, I still find it always rewarding to understand what is really going on.
So, here we go.
First and foremost: The Svelte tutorial has a useful feature to let you see the generated code (right next to the "Result" pane). It might look a bit intimidating at first, but you quickly get the hang of it.
Below code will be based on this example (but further simplified): Svelte tutorial - reactivity/assignments
Our example component definition (i.e. App.svelte) looks like this:
<script>
let count = 0;
function handleClick() {
count += 1;
}
</script>
<button on:click={handleClick}>{count}</button>
Based on this component definition, the Svelte compiler creates a function which will create a "fragment" which receives and interacts with a "context".
function create_fragment(ctx) {
let button;
let t;
let dispose;
return {
c() {
button = element("button");
t = text(/*count*/ ctx[0]);
dispose = listen(button, "click", /*handleClick*/ ctx[1]);
},
m(target, anchor) {
insert(target, button, anchor);
append(button, t);
},
p(ctx, [dirty]) {
if (dirty & /*count*/ 1) set_data(t, /*count*/ ctx[0]);
},
i: noop,
o: noop,
d(detaching) {
if (detaching) detach(button);
dispose();
}
};
}
The fragment is responsible to interact with the DOM and will be passed around with the component instance. In a nutshell, the code inside
"c" will be run on create (creating the DOM elements in memory and also setting up the event handlers)
"m" will run on mount (attaching the elements to the DOM)
"p" will run on update, i.e. when something (including props) changes
"i" / "o" are related to intro/outro (i.e. transitions)
"d" will be run on destroy
Note: The functions like element or set_data are actually very approachable.
For example, the function element is just a wrapper around document.createElement:
function element(name) {
return document.createElement(name);
}
The context (ctx) will hold all instance variables as well as functions. It is nothing more than a simple array. Since Svelte "knows" what each index means at compile time, it can make hard references to the indices at other places.
This code essentially defines the instance context:
function instance($$self, $$props, $$invalidate) {
let count = 0;
function handleClick() {
$$invalidate(0, count += 1);
}
return [count, handleClick];
}
Both the instance method as well as the create_fragment will be called from another function call init. It's a bit more involved, so instead of copy and pasting it here, you can have a look at this link to the source.
The $$invalidate will make sure that the count variable is set as dirty and schedule an update. When the next update runs, it will look at all "dirty" components and update them. How this is happening is really more of an implementation detail. If interested, set a breakpoint in the flush function.
In fact, if you really want to go a bit deeper, I recommend to clone the template app, then create a simple component, have it compiled and then inspect "bundle.js". You can also debug the actual code if you either delete the source maps or deactivate them.
So, for example set the rollup.config.js like so:
output: {
sourcemap: false,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js'
},
plugins: [
svelte({
dev: false,
Note: As shown above, I recommend to also set dev mode to false since this will create more concise code.
One neat feature: Once our app is running, you can also access the app variable (it is assigned to the global window object since it is bundled as an immediately-invoked function expression).
So, you can open your console and simply say
console.dir(app)
which will produce something like this
App
$$:
fragment: {c: ƒ, m: ƒ, p: ƒ, i: ƒ, o: ƒ, …}
ctx: (2) [0, ƒ]
props: {count: 0}
update: ƒ noop()
not_equal: ƒ safe_not_equal(a, b)
bound: {}
on_mount: []
on_destroy: []
before_update: []
after_update: []
context: Map(0) {}
callbacks: {}
dirty: [-1]
__proto__: Object
$set: $$props => {…}
One cool feature is that you can the $set method yourself to update the instance. For example like so:
app.$set({count: 10})
There are also Svelte DevTools which try to make the internals of Svelte more approachable. Somehow, they seemed to affect the render performance of my apps when I personally tried them out, so I don't use them myself. But certainly something to watch.
Well, there you have it. I know this is still rather technical, but I hope it helped to get a better understanding on what compiled Svelte code is doing.
Both libraries minimize how many changes need to be made to the dom. The difference is the way that they figure out what that minimal set of changes is.
React's approach is to have a representation of the dom in memory (the virtual dom). When you set state, it runs the render process again to create another virtual dom. It compares the before and after, finds what changed, and then any changes get pushed to the real dom.
Svelte's approach is that when you set a variable, it sets a flag marking that variable as having changed. It knows which variables are dependent on other variables, so it then steps through any dependent variables and recalculates them, building up a list of what needs to change. Then these changes get pushed to the dom.

restangular save ignores changes to restangular object

I'm trying to call save on a restangularized object, but the save method is completely ignoring any changes made to the object, it seems to have bound the original unmodified object.
When I run this in the debugger I see that when my saveSkill method (see below) is entered right before I call save on it the skill object will reflect the changes I made to it's name and description fields. If I then do a "step into" I go into Restangular.save method. However, the 'this' variable within the restangular.save method has my old skill, with the name and description equal to whatever they were when loaded. It's ignoring the changes I made to my skill.
The only way I could see this happening is if someone called bind on the save, though I can't why rectangular would do that? My only guess is it's due to my calling $object, but I can't find much in way of documentation to confirm this.
I'm afraid I can't copy and paste, all my code examples are typed by hand so forgive any obvious syntax issues as typos. I don't know who much I need to describe so here is the shortened version, I can retype more if needed:
state('skill.detail', {
url: '/:id',
data: {pageTitle: 'Skill Detail'},
tempalte: 'template.tpl.html'
controller: 'SkillFormController',
resolve: {
isCreate: (function(){ return false;},
skill: function(SkillService, $stateParams){
return SkillService.get($stateParams.id, {"$expand": "people"}).$object;
},
});
my SkillService looks like this:
angular.module('project.skill').('SkillService', ['Restangular, function(Retangular) {
var route="skills";
var SkillService= Restangular.all(route);
SkillService.restangularize= function(element, parent) {
var skill=Restangular.restangluarizeElement(parent, elment, route);
return skill;
};
return SkillService;
}];
Inside of my template.tpl.html I have your standard text boxes bound to name and description, and a save button. The save button calls saveSkill(skill) of my SkillFormController which looks like this:
$scope.saveSkill=function(skill) {
skill.save().then(function returnedSkill) {
toaster.pop('success', "YES!", returnedSkill.name + " saved.");
...(other irrelevant stuff)
};
If it matters I have an addElementTransformer hook that runs a method calling skilll.addRestangularMethod() to add a getPeople method to all skill objects. I don't include the code since I doubt it's relevant, but if needed to I can elaborate on it.
I got this to work, though I honestly still don't know entirely why it works I know the fix I used.
First, as stated in comments restangular does bind all of it's methods to the original restangularizedObject. This usually works since it's simply aliasing the restangularied object, so long as you use that object your modifications will work.
This can be an issue with Restangular.copy() vs angular.copy. Restangualar.copy() makes sure to restangularize the copied object properly, rebinding restangualr methods to the new copy objects. If you call only Angular.copy() instead of Restangualar.copy() you will get results like mine above.
However, I was not doing any copy of the object (okay, I saved a master copy to revert to if cancel was hit, but that used Restangular.copy() and besides which wasn't being used in my simple save scenario).
As far as I can tell my problem was using the .$object call on the restangular promise. I walked through restangular enough to see it was doing some extra logic restangularizing methods after a promise returns, but I didn't get to the point of following the $object's logic. However, replacing the $object call with a then() function that did nothing but save the returned result has fixed my issues. If someone can explain how I would love to update this question, but I can't justify using work time to try to further hunt down a fixed problem even if I really would like to understand the cause better.

Mocha tests on focus-related behaviors (Backbone/CoffeeScript app)

I have a Backbone app written in CoffeeScript. I'm trying to use Mocha (with Chai and Sinon) to write tests for DOM-related behaviors, but it seems that hidden fixtures (I'm using js-fixtures now but I've also tried this unsuccessfully with a hidden '#fixtures' div) don't register certain DOM-related behaviors which makes testing certain types of DOM-related behaviors (seemingly) impossible.
For example, my main app view has several subviews which are never rendered at the same time: when the app view renders subview A, it remembers the focused element of the currently active subview B (#_visibleView), saves that information on subview B, closes the subview B, and then renders subview A.
_rememberFocusedElement: ->
focusedElement = $ document.activeElement
if focusedElement
focusedElementId = focusedElement.attr 'id'
if focusedElementId
#_visibleView?.focusedElementId = focusedElementId
This works when I test it manually, but when I try to write unit tests for this behavior they fail because I can't set focus (e.g., via $(selector).focus()) to an element in a hidden div/iframe. (I have the same issue with functionality which listens for window resize events.)
I thought that if I changed $ document.activeElement to #$ ':focus" I might get different results, but that doesn't fix the issue.
Here is what the relevant parts of my Mocha (BDD) tests look like. This spec will print TEXTAREA to the console and then undefined, indicating that there is a textarea with id='transcription' but I can't set focus to it.
beforeEach (done) ->
fixtures.path = 'fixtures'
callback = =>
#$fixture = fixtures.window().$ "<div id='js-fixtures-fixture'></div>"
#appView = new AppView el: #$fixture
done()
describe 'GUI stuff', ->
it 'remembers the currently focused element of a subview', (done) ->
#appView.mainMenuView.once 'request:formAdd', =>
#appView._visibleView.$('#transcription').focus()
console.log #appView._visibleView.$('#transcription').prop 'tagName'
console.log #appView._visibleView.$(':focus').prop 'tagName'
done()
#appView.mainMenuView.trigger 'request:formAdd'
Is there any way that I can write unit tests for these types of behaviors?
Ok, first off let me clarify something: the term "unit test" means man different things to many people. Often times it becomes synonymous with "any test written using a unit test framework (like Mocha)". When I use the term "unit test" that's not what I mean: what I mean is a test that tests only a single unit of work (which, in a JS environment, will usually be a single function, but might be a whole class).
Ok, with that out of the way, if you really are trying to unit test your code, you're sort of taking the wrong approach. A unit test really shouldn't rely on anything outside the context of the function being tested, and so relying on the (external) DOM is where your problem lies.
Let's assume your focus-handling code is in a function called handleFocus (I don't know the actual method name). Consider the following test, which I'll write using JavaScript since my CoffeScript is rusty:
describe('#handleFocus', function() {
it('remembers the currently focused element of a subview', function() {
var setFocusStub = sinon.stub($.fn, 'focus');
appView._visibleView.handleFocus();
expect(setFocusStub.calledOnce).to.be(true);
});
});
The above is a bit of an over-simplification, but hopefully it illustrates the point. What you're really trying to check isn't whether the DOM (fake or real) does X; what you're trying check is whether your function does X. By focusing on that in your test, and relying on a stub that checks whether "X" happened or not, you completely eliminate the need for the DOM to be involved.
Now of course you might wonder: "well great, that helps me in test-land, but how do I know it will work in a real environment?" My answer to that would be that your (probably Selenium-based) acceptance tests should cover that sort of thing. Acceptance tests should check whether your overall code works in the real world, while unit tests should ensure that individual pieces of that code work in a fake environment.
The former is great for ensuring your customers don't see bugs, while the latter is great for figuring out exactly where those bugs come from, and for making it possible for you to refactor safely.

Is there a way to log the JavaScript stack trace without putting breakpoints?

I would like to be able to perform manipulations on a given JS app, and then simply get a large log of all the functions that have been called. This is possible in Chrome, but only if one puts a breakpoint somewhere. My problem is when I am reverse-engineering a given website (only for self-teaching purposes, of course) it often takes me a whole lot of time to figure out where to even start from. Something like that will help me tremendously because I will no longer have to search within the code, rather, I will just do a user action, and grab the stack log afterwards.
I suppose that there should be a way to intercept (or wrap) every function call, so that it is dumped to the log before the function is called.
Try this article:
http://eriwen.com/javascript/stacktrace-update/
or this post:
http://ivan-ghandhi.livejournal.com/942493.html
and, probably, this: How can I get a Javascript stack trace when I throw an exception?
In Firebug, you can use the profiler to log every function called. Use console.profile() and console.profileEnd() to trigger it programatically.
However, this will not give you proper stack traces. (Are you sure that's what you want?)
To log methods of specific objects, you can overwrite them like so:
for (var key in obj) {
if (typeof obj[key] == 'function') {
(function(){
var origFun = obj[key];
obj[key] = function () {
var result = origFun.apply(this, arguments);
console.log('call to method', key, 'with arguments', arguments,' - Result:', result);
// console.trace(); // for a trace with every call
return result;
};
})();
}
}
Maybe aspect oriented programming (AOP) can provide an answer. I just found out about aspectJS which could help intercept and log function calls
You can use dynatrace. Dynatrace is a profiling tool for IE and FF. Dynatrace can monitor your application while it is running, and then serves you a timeline of all what happened. In the timeline, there is blocks representing the javascript activity. You can right-click on it (purepath), and then walk through the whole call stack. You can export that to excel or other If you want.
You can add markers in your code, those markers will appear on the timeline and in the purepath:
if(typeof(_dt_addMark)!="undefined") _dt_addMark('MyCustomTimerName');
alternatively, if you only want to find "a way to intercept (or wrap) every function call",
there is a low-tech solution, if you are using a real webbapp (single-load javascript app):
bookmarklets
With bookmarklets, once you have loaded your page, you can execute some custom javascript. So what you can do there, is to override the functions methods that you want to observe with the same function containing logging (so just copy and paste the function, and add some console.log in there). This actually works even with native js functions.

Categories

Resources