Trying to limit the number of times my updateLocation() function is called below. My understanding is that debounce would limit the calls to 1 every 5 seconds, yet the method never gets hit - debounce seems to debounce everything?
var id = navigator.geolocation.watchPosition(function (location) {
_.debouce(function () {
updateLocation(location);
}, 5000);
}, function (err) {
console.log(err);
}, {enableHighAccuracy: false, timeout: 5000, maximumAge: 0});
Call debounce once and use the returned value as the success handler:
var successHandler = _.debouce(updateLocation, 5000);
var id = navigator.geolocation.watchPosition( successHandler, ....
What's happening in your code is that you're creating a debounced function every time the position changes.
Related
I'm building a system resource monitor as a project using electron and aurelia.
Main.js
var ramInfo = {};
var result = await si.mem()
ramInfo.total = parseInt(result.total / 1024 / 1024);
ramInfo.used = parseInt(result.used / 1024 / 1024);
ramInfo.percentUsed = parseInt((ramInfo.used / ramInfo.total) * 100);
ramInfo.percentAvailable = parseInt((ramInfo.percentUsed - 100) * -1);
event.sender.send('ram-reply', ramInfo);
})
Overview.js:
async attached () {
await this.getRamInfo();
this.startDataRefresh();
}
async getRamInfo () {
window.ipc.send('ram');
await window.ipc.on('ram-reply', (event, result) => {
this.system.ram = result;
//This line gets logged an additional time each time the setInterval function runs
console.log(this.system.ram);
this.ramData.series = [this.system.ram.percentAvailable, this.system.ram.percentUsed];
new Chartist.Pie('.ram-chart', this.ramData , this.options);
});
console.log("Break");
}
startDataRefresh() {
let scope = this;
setInterval(function() {
scope.getRamInfo();
}, 3000);
}
I am receiving the folowing error in my electron console:
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 ram-reply listeners added to [EventEmitter]. Use emitter.setMaxListeners() to increase limit
I would only think that the getRamInfo() function would run once every three seconds, however, the console.log portion of the function is getting logged an additional time each time the function runs. I'm fairly certain this is where the issue lies, I'm just not sure why it is running multiple times per interval.
EDIT:
I've reached a partial solution in moving the setInterval function into main.js:
ipcMain.on('ram', async (event) => {
setInterval(async function() {
var ramInfo = {};
var result = await si.mem()
ramInfo.total = parseInt(result.total / 1024 / 1024);
ramInfo.used = parseInt(result.used / 1024 / 1024);
ramInfo.percentUsed = parseInt((ramInfo.used / ramInfo.total) * 100);
ramInfo.percentAvailable = parseInt((ramInfo.percentUsed - 100) * -1);
event.sender.send('ram-reply', ramInfo)
}, 3000);
})
It seems like each time the original setInterval called to ipcMain this created a new listener and each time every listener returned the results. I would like it to be dependant on the view that is open so controlling this via the view would be preferable.
Try this:
async getRamInfo () {
window.ipc.send('ram');
return new Promise(resolve => window.ipc.once('ram-reply', (event, result) => resolve(result));
}
async refresh() {
const ramInfo = await this.getRamInfo();
this.ramData.series = [this.system.ram.percentAvailable, this.system.ram.percentUsed];
new Chartist.Pie('.ram-chart', this.ramData , this.options);
// ...
}
startDataRefresh() {
if(!this.interval) {
this.interval = setInterval(() => this.refresh(), 3000);
}
}
stopDataRefresh() {
if(this.interval) {
clearInterval(this.interval);
delete this.interval;
}
}
main part - window.ipc.once('ram-reply' - use once for one-time event subscription
Is it possible to reset/increase the timeout of an Observable after another timeout has already been set? In the following example the timeout of 5 should be overriden with a timeout of 9999, but this does not work:
var source = Rx.Observable
.return(42)
.delay(1000)
.timeout(5)
.timeout(9999); // this statement should override the previous set timeout of 5 MS, but actually it does not
var subscription = source.subscribe(
function (x) {
console.log('Next: ' + x);
},
function (err) {
console.log('Error: ' + err);
},
function () {
console.log('Completed');
});
Are there any possibilities to override the already set timeout?
Short answer: As far as I know, there is no "legit" solution to this.
Hacky answer: You could connect to the source of the timeout-ed stream and set your own timeout, see the example below how this could be done.
However, I would not advise you to do that in any seriouse project - I'm sure there should be another solution to your problem.
var base = Rx.Observable
.return(42)
.delay(1000)
.timeout(1);
var patched = base.source.timeout(2000);
var subscription = patched.subscribe(
function (x) {
console.log('Patched Next: ' + x);
},
function (err) {
console.log('Patched Error: ' + err);
},
function () {
console.log('Patched Completed');
});
var subscription = base.subscribe(
function (x) {
console.log('Base Next: ' + x);
},
function (err) {
console.log('Base Error: ' + err);
},
function () {
console.log('Base Completed');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.1.0/rx.all.js"></script>
What about if you use a subject to represent your timeout value?
timeoutSubject = new Rx.ReplaySubject(1);
timeoutSubject
.asObservable()
.switchMap((v) => source.timeout(v))
.subscribe((r) => console.log(r));
timeoutSubject.next(5);
timeoutSubject.next(9999);
switchMap should take handle of the unsubscribing/resubscribing for each one of the timeout values.
Could some genius help on this issue to sort it out!!! It will be much appreciated
Actually I have flash music player loaded by means of config file named config.xml
Flash player Action script example
**myUltimateMp3Player.loadConfig("config.xml");**
import flash.external.ExternalInterface;
stop();
// ExternalInterface receive
if (ExternalInterface.available) {
ExternalInterface.addCallback("sendTextFromHtml", null, function(val:String):Void {
myUltimateMp3Player.loadConfig(val); });
}
I'm tried to embed the flash dynamically using Swf object,so when a click event handled from a list from html, the corresponding config.xml should be loaded on the flash player.
Sample HTML code:
$( document ).on( "click", "#Musiclist li", function() {
var c = "youtube-playlist";
$("#media-" + c).remove();
createMedia(c);
var id=this.id;
var idxml=id+".xml";
var swfPanel="media-" + c;
var flashvars = {};
var params = {};
params.swliveconnect = "true";
params.allowfullscreen = "true";
params.allowscriptaccess = "always";
var attributes = {};
attributes.id = "flashobj";
attributes.name = "flashobj";
swfobject.embedSWF("source.swf", "flashcontent", "100%", "100%", "9.0.0", "swf/expressInstall.swf", flashvars, params, attributes,callbackFn);
});
callback function
//This function is invoked by SWFObject once the <object> has been created
var callbackFn = function (e){
//Only execute if SWFObject embed was successful
if(!e.success || !e.ref){ return false; }
swfLoadEvent(function(){
var obj=e.ref;
obj.sendTextFromHtml("config.xml");
alert("The SWF has finished loading!");
});
};
Function to hold timer for SWF's PercentLoaded value and waits until it hits "100"
function swfLoadEvent(fn){
//Ensure fn is a valid function
if(typeof fn !== "function"){ return false; }
//This timeout ensures we don't try to access PercentLoaded too soon
var initialTimeout = setTimeout(function (){
//Ensure Flash Player's PercentLoaded method is available and returns a value
if(typeof e.ref.PercentLoaded !== "undefined" && e.ref.PercentLoaded()){
//Set up a timer to periodically check value of PercentLoaded
var loadCheckInterval = setInterval(function (){
//Once value == 100 (fully loaded) we can do whatever we want
if(e.ref.PercentLoaded() === 100){
//Execute function
fn();
//Clear timer
clearInterval(loadCheckInterval);
}
}, 1500);
}
}, 200);}
So I cant figure it out what I'm doing wrong,
The error getting was,
Uncaught ReferenceError: e is not defined
If I'm not using the swfLoadEvent Timer,
The error getting was,
Uncaught TypeError: Object # has no method 'sendTextFromHtml'
e is not a global variable. try modifying your swfLoadEvent function to pass a reference to the swf as an argument:
function swfLoadEvent(swf, fn){
swf.sendTextFromHtml("config.xml");
...
}
which then gets invoked as
swfLoadEvent(e.ref, function(){
...
});
Are there any events fired by an element to check whether a css3 transition has started or end?
W3C CSS Transitions Draft
The completion of a CSS Transition generates a corresponding DOM Event. An event is fired for each property that undergoes a transition. This allows a content developer to perform actions that synchronize with the completion of a transition.
Webkit
To determine when a transition completes, set a JavaScript event listener function for the DOM event that is sent at the end of a transition. The event is an instance of WebKitTransitionEvent, and its type is webkitTransitionEnd.
box.addEventListener( 'webkitTransitionEnd',
function( event ) { alert( "Finished transition!" ); }, false );
Mozilla
There is a single event that is fired when transitions complete. In Firefox, the event is transitionend, in Opera, oTransitionEnd, and in WebKit it is webkitTransitionEnd.
Opera
There is one type of transition event
available. The oTransitionEnd event
occurs at the completion of the
transition.
Internet Explorer
The transitionend event occurs at the completion of the transition. If the transition is removed before completion, the event will not fire.
Stack Overflow: How do I normalize CSS3 Transition functions across browsers?
Update
All modern browsers now support the unprefixed event:
element.addEventListener('transitionend', callback, false);
https://caniuse.com/#feat=css-transitions
I was using the approach given by Pete, however I have now started using the following
$(".myClass").one('transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd',
function() {
//do something
});
Alternatively if you use bootstrap then you can simply do
$(".myClass").one($.support.transition.end,
function() {
//do something
});
This is becuase they include the following in bootstrap.js
+function ($) {
'use strict';
// CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
// ============================================================
function transitionEnd() {
var el = document.createElement('bootstrap')
var transEndEventNames = {
'WebkitTransition' : 'webkitTransitionEnd',
'MozTransition' : 'transitionend',
'OTransition' : 'oTransitionEnd otransitionend',
'transition' : 'transitionend'
}
for (var name in transEndEventNames) {
if (el.style[name] !== undefined) {
return { end: transEndEventNames[name] }
}
}
return false // explicit for ie8 ( ._.)
}
$(function () {
$.support.transition = transitionEnd()
})
}(jQuery);
Note they also include an emulateTransitionEnd function which may be needed to ensure a callback always occurs.
// http://blog.alexmaccaw.com/css-transitions
$.fn.emulateTransitionEnd = function (duration) {
var called = false, $el = this
$(this).one($.support.transition.end, function () { called = true })
var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
setTimeout(callback, duration)
return this
}
Be aware that sometimes this event doesn’t fire, usually in the case
when properties don’t change or a paint isn’t triggered. To ensure we
always get a callback, let’s set a timeout that’ll trigger the event
manually.
http://blog.alexmaccaw.com/css-transitions
All modern browsers now support the unprefixed event:
element.addEventListener('transitionend', callback, false);
Works in the latest versions of Chrome, Firefox and Safari. Even IE10+.
In Opera 12 when you bind using the plain JavaScript, 'oTransitionEnd' will work:
document.addEventListener("oTransitionEnd", function(){
alert("Transition Ended");
});
however if you bind through jQuery, you need to use 'otransitionend'
$(document).bind("otransitionend", function(){
alert("Transition Ended");
});
In case you are using Modernizr or bootstrap-transition.js you can simply do a change:
var transEndEventNames = {
'WebkitTransition' : 'webkitTransitionEnd',
'MozTransition' : 'transitionend',
'OTransition' : 'oTransitionEnd otransitionend',
'msTransition' : 'MSTransitionEnd',
'transition' : 'transitionend'
},
transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
You can find some info here as well http://www.ianlunn.co.uk/blog/articles/opera-12-otransitionend-bugs-and-workarounds/
Just for fun, don't do this!
$.fn.transitiondone = function () {
return this.each(function () {
var $this = $(this);
setTimeout(function () {
$this.trigger('transitiondone');
}, (parseFloat($this.css('transitionDelay')) + parseFloat($this.css('transitionDuration'))) * 1000);
});
};
$('div').on('mousedown', function (e) {
$(this).addClass('bounce').transitiondone();
});
$('div').on('transitiondone', function () {
$(this).removeClass('bounce');
});
If you simply want to detect only a single transition end, without using any JS framework here's a little convenient utility function:
function once = function(object,event,callback){
var handle={};
var eventNames=event.split(" ");
var cbWrapper=function(){
eventNames.forEach(function(e){
object.removeEventListener(e,cbWrapper, false );
});
callback.apply(this,arguments);
};
eventNames.forEach(function(e){
object.addEventListener(e,cbWrapper,false);
});
handle.cancel=function(){
eventNames.forEach(function(e){
object.removeEventListener(e,cbWrapper, false );
});
};
return handle;
};
Usage:
var handler = once(document.querySelector('#myElement'), 'transitionend', function(){
//do something
});
then if you wish to cancel at some point you can still do it with
handler.cancel();
It's good for other event usages as well :)
I am building a firefox addon that loads javascript at every page load. I'm using progress listener function I found on this page: https://developer.mozilla.org/en/Code_snippets/Progress_Listeners
My problem is that the code seems to execute to early before the page is fully loaded which causes my script to not run. Here is my code.
var PageLoad = {
browser: null,
domain: null,
oldURL: null,
init: function() {
gBrowser.addProgressListener(urlBarListener,Components.interfaces.nsIWebProgress.NOTIFY_LOCATION);
},
uninit: function() {
gBrowser.removeProgressListener(urlBarListener);
},
processNewURL: function(aURI) {
//if (aURI.spec == this.oldURL)
//return;
MyObject.function();
this.oldURL = aURI.spec;
}
};
var urlBarListener = {
locChange: false,
QueryInterface: function(aIID) {
if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
aIID.equals(Components.interfaces.nsISupports))
return this;
throw Components.results.NS_NOINTERFACE;
},
onLocationChange: function(aProgress, aRequest, aURI) {
PageLoad.processNewURL(aURI);
},
onStateChange: function(aWebProgress, aRequest, aFlag, aStatus) {},
onProgressChange: function(a, b, c, d, e, f) {},
onStatusChange: function(a, b, c, d) {},
onSecurityChange: function(a, b, c) {}
};
window.addEventListener("load",
function() {
PageLoad.init()
}, false);
var MyObject = {
function : function() {
var script = PageLoad.browser.createElement('script');
script.src = 'url_to_script.js';
PageLoad.browser.getElementsByTagName('head')[0].appendChild(script);
}
};
With this code I get this error message on the console:
PageLoad.browser.getElementByTagName("head")[0] is undefined
If I add a timeout then the script does work intermittently but if the page loads slow I get the same error, here's what works sometimes setTimeout(MyObject.function, 1000);
I need a more reliable way of making sure it's executing the script after the page is loaded.
Unrelated, and it doesn't seem to cause any problems but I also see this error message:
gBrowser.addProgressListener was called with a second argument, which is not supported. See bug 608628.
If you want to load javascript at every page load - the best way is subscribing to DOMContentLoaded event:
var MyObject = {
processDOMContentLoaded: function(doc) {
var script = doc.createElement('script');
script.src = 'url_to_script.js';
script.type = 'text/javascript';
doc.getElementsByTagName('head')[0].appendChild(script);
}
};
window.addEventListener('load', function() {
var appcontent = document.getElementById('appcontent');
if(appcontent != null) {
appcontent.addEventListener('DOMContentLoaded', function(event) {
var doc = event.originalTarget;
if(doc instanceof HTMLDocument) {
MyObject.processDOMContentLoaded(doc);
}
}, true);
}
}, false);
Have not tested, but should work.
You are using onLocationChange method - but if you look at how the browser behaves, the location in the address bar changes as soon as a connection with the server is established. You should look at state changes instead:
onStateChange: function(aWebProgress, aRequest, aFlag, aStatus)
{
if ((aFlag & Components.interfaces.nsIWebProgressListener.STATE_STOP) &&
(aFlag & Components.interfaces.nsIWebProgressListener.STATE_IS_WINDOW))
{
// A window finished loading
PageLoad.windowLoaded(aWebProgress.DOMWindow);
}
},
Note that the window that finished loading is explicitly passed to PageLoad.windowLoaded() - you will be receiving notifications from different tabs and you cannot assume that the notification comes from the foreground tab.
As to the warning you are getting, just leave out the second parameter in the call to gBrowser.addProgressListener():
gBrowser.addProgressListener(urlBarListener);
tabbrowser.addProgressListener() only accepts one parameter, unlike nsIWebProgress.addProgressListener() which has a second parameter.
Actually its a great question.
You should use event listener, but carefully, because if you trigger for every page load its can trigger you more than one time (in the worst case about dozens of times).
So how you can do that?
window.addEventListener("load", function load(event){
window.removeEventListener("load", load, false); //remove listener, no longer needed
myExtension.init();
},false);
var myExtension = {
init: function() {
var appcontent = document.getElementById("appcontent"); // browser
if(appcontent){
appcontent.addEventListener("DOMContentLoaded", myExtension.onPageLoad, true);
}
},
onPageLoad: function(aEvent) {
var doc = aEvent.originalTarget; // doc is document that triggered the event
var win = doc.defaultView; // win is the window for the doc
if (doc.nodeName != "#document") return;
if (win != win.top) return;
if (win.frameElement) return;
alert("the main page has been loaded");
},
};
get notice that we check for the type of the trigger every pageload triggering to prevent multi load.
The answers that were provided were acceptable but I found yet another solution that works perfectly.
var PageLoad = {
init: function() {
if(gBrowser) gBrowser.addEventListener("DOMContentLoaded", this.onPageLoad, false);
},
onPageLoad: function(aEvent) {
var doc = aEvent.originalTarget; // doc is document that triggered the event
var win = doc.defaultView; // win is the window for the doc
if (doc.nodeName != "#document") return;
if (win != win.top) return;
if (win.frameElement) return;
MyAddon.function();
}
}
window.addEventListener("load", function load(event){
window.removeEventListener("load", load, false); //remove listener, no longer needed
PageLoad.init();
},false);