function addAndRemove() {
if (mapData.initialZoom && !cameraStatus.locked) {
cameraStatus.locked = true;
var ajaxRequest = null;
var abortMission = setTimeout(function () {
/* Here is where I need the event listener.
* If the function is called again then we need to
* cancel our existing ajax request */
if (ajaxRequest) {
ajaxRequest.abort();
updatePrompt({text: "Cancelled ajax"});
}
cameraStatus.locked = false;
}, 1000);
}
}
As I have stated in a comment in the code I need to be able to listen out to see if addAndRemove is called again whilst in execution. I only want to cancel the existing Ajax request if a new one has been requested. How can I do this?
You need to use a closure to create a state in your function.
You could refactor your function this way.
var addAndRemove = (function(){
var ajaxRequest = null; // --> move ajaxRequest variable here
return function () {
if (mapData.initialZoom && !cameraStatus.locked) {
cameraStatus.locked = true;
var abortMission = setTimeout(function () {
/* Here is where I need the event listener.
* If the function is called again then we need to
* cancel our existing ajax request */
if (ajaxRequest) {
ajaxRequest.abort();
updatePrompt({text: "Cancelled ajax"});
}
cameraStatus.locked = false;
}, 1000);
}
}
}());
that way ajaxRequest will point to the same reference no matter how much time your function is called.
Related
I've been running into some performance issues when a scroll event gets fired on a project i'm working on and found that debouncing the taxing stuff would be a viable solution:
jQuery(document).ready(function() {
jQuery(window).on('scroll', debounce(function(e) {
console.log('debounced');
console.log(e); // will print the corresponding jQuery object
// some heavy work
}, 250, true)
);
});
function debounce(func, wait, immediate) {
var timeout;
return function() {
var obj = this, args = arguments;
if (timeout) clearTimeout(timeout);
else if (immediate) func.apply(obj, args);
timeout = setTimeout(function() {
if (!immediate) func.apply(obj, args);
timeout = null;
}, wait || 100);
};
};
My question is, how come the jQuery event object is properly handed over within debounce() ?
Isn't it supposed to be passed as first argument of function set as handler, here being debounce() ?
This solution seems to get the job done just fine, but is there some conceptual thing i'm missing here ?
NB: credits to John Hann for the debouncing function
Answer is that jquery event gets return of debounce function, in return it has anonymous function so it exacly what event want to get in parameters.
var exampleFunc=function(){
return 1;
};
var a = exampleFunc; //a is exampleFunc reference
a= exampleFunc(); // a is return value of exampleFunc = 1
Some examples the same behavior:
$('el').on("click",function(e){ /* do something */ })
is the same as
someFunc=function(){ /* do something */ };
$('el').on("click",someFunc);
and is the same:
someFunc=function(){ /* do something */ };
someFunc2=function(){ /* do something 2 */ return someFunc; };
$('el').on("click",someFunc2());
and ... the same as:
someFunc2=function(){
/* do something 2 */
return function(){ /* do something */ }
};
$('el').on("click",someFunc2());
Conclusion - using function in next function is using its return value.
var a=5;
var getA(){ return 5; };
var twentyfive=a*getA(); //25
Some example of using function return as another function:
//EXAMPLE NESTED FUNCTION
var funcNested=function(){
console.log("It is funcNested ");
};
var func=function(){ return funcNested; };
$("#test").on("click",func());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="test">Click me</button>
I have this function. The purpose is to wait for an outside status to end before calling another function.
var renderEditClickWrapper = function( event )
{
var wait = false;
function waitForSavingDone(){
if (options.dataStatusHandler.getStatus() == 'saving'){
wait = setInterval( function(){
waitForSavingDone();
}, 800);
}else{
wait = false;
call.renderEdit(event.data.name, event.data.rowId, event.data.parentId, event.data.options );
}
}
if (!wait) waitForSavingDone();
return false;
};
This works, however when the functions waits once, the function is called over and over.
I'm using jQuery as well.
Any idea what I am doing wrong?
Here is one more alternative you may try:
Define a wait function as below:
function wait(waitComplete, onWaitComplete){
if (waitComplete()) {
onWaitComplete();
return true;
}
setTimeout(function(){
console.log('waiting...');
wait(waitComplete, onWaitComplete);
}, 800);
return false;
}
Event handler can use wait as below:
var renderEditClickWrapper = function( event )
{
function isWaitComplete() {
return (options.dataStatusHandler.getStatus() != 'saving');
}
function onWaitComplete() {
call.renderEdit(event.data.name, event.data.rowId,
event.data.parentId, event.data.options);
}
wait(isWaitComplete, onWaitComplete);
};
Try using clearInterval() method to cancel the interval function, instead of wait = false. And also you misunderstood the usage of interval functions. Do it like below:
var renderEditClickWrapper = function( event )
{
function waitForSavingDone() {
if (options.dataStatusHandler.getStatus() !== 'saving') {
clearInterval(wait);
}
}
var wait = setInterval(waitForSavingDone, 800);
return false;
};
You should check the callback function as mentioned in the comments. It'll be more recommended if you use callback instead.
Due to certain reason, we are going to remove jquery from our legacy app (Please don't ask why!)
However, there 1000+ of template files by designers, are making used of jquery ready function. We plan to make the following mock strategy.
<head>
<script type="text/javascript">
// // http://stackoverflow.com/a/9899701
(function(funcName, baseObj) {
// The public function name defaults to window.docReady
// but you can pass in your own object and own function name and those will be used
// if you want to put them in a different namespace
funcName = funcName || "docReady";
baseObj = baseObj || window;
var readyList = [];
var readyFired = false;
var readyEventHandlersInstalled = false;
// call this when the document is ready
// this function protects itself against being called more than once
function ready() {
if (!readyFired) {
// this must be set to true before we start calling callbacks
readyFired = true;
for (var i = 0; i < readyList.length; i++) {
// if a callback here happens to add new ready handlers,
// the docReady() function will see that it already fired
// and will schedule the callback to run right after
// this event loop finishes so all handlers will still execute
// in order and no new ones will be added to the readyList
// while we are processing the list
readyList[i].fn.call(window, readyList[i].ctx);
}
// allow any closures held by these functions to free
readyList = [];
}
}
function readyStateChange() {
if (document.readyState === "complete") {
ready();
}
}
// This is the one public interface
// docReady(fn, context);
// the context argument is optional - if present, it will be passed
// as an argument to the callback
baseObj[funcName] = function(callback, context) {
// if ready has already fired, then just schedule the callback
// to fire asynchronously, but right away
if (readyFired) {
setTimeout(function() {
callback(context);
}, 1);
return;
} else {
// add the function and context to the list
readyList.push({
fn: callback,
ctx: context
});
}
// if document already ready to go, schedule the ready function to run
if (document.readyState === "complete") {
setTimeout(ready, 1);
} else if (!readyEventHandlersInstalled) {
// otherwise if we don't have event handlers installed, install them
if (document.addEventListener) {
// first choice is DOMContentLoaded event
document.addEventListener("DOMContentLoaded", ready, false);
// backup is window load event
window.addEventListener("load", ready, false);
} else {
// must be IE
document.attachEvent("onreadystatechange", readyStateChange);
window.attachEvent("onload", ready);
}
readyEventHandlersInstalled = true;
}
}
})("docReady", window);
// Mock jquery.
var jQuery = function(baseObj) {
return {
ready: function(baseObj) {
docReady(baseObj);
}
}
};
var $ = jQuery;
</script>
</head>
Take note, we tend to mock jquery ready with the following code snippet.
// Mock jquery.
var jQuery = function (baseObj) {
return {
ready: function (baseObj) {
docReady(baseObj);
}
}
};
var $ = jQuery;
It works for cases
jQuery(document).ready(function() {...});
$(document).ready(function() {...});
However, how can we make the following syntax works as well?
$(function() {...});
Check if the passed parameter is function
var jQuery = function(baseObj) {
if (typeof baseObj === 'function')
return docReady(baseObj);
Code:
// Mock jquery.
var jQuery = function (baseObj) {
if (typeof baseObj === 'function')
return docReady(baseObj);
return {
ready: function (baseObj) {
docReady(baseObj);
}
}
};
var $ = jQuery;
In the third case you are actually not calling the ready function. As it is just bind a function in it .
$(function() {...});
So the below function is not called , you are just return an object function which is not called.
var jQuery = function (baseObj) {
return {
ready: function (baseObj) {
docReady(baseObj);
}
}
};
You need to called the function directly for the third case, as below.
// Mock jquery.
var jQuery = function (baseObj) {
if (typeof(baseObj) === 'function') docReady(baseObj);
return {
ready: function (baseObj) {
docReady(baseObj);
}
}
};
Demo : http://jsfiddle.net/kishoresahas/vnd92c1u/
I also had alike situation, a some what similar code is live for long now.
Code Example:
define(function() {
var self = this,
saveTimer = null,
saveFunction = null,
timer_sleep = 0;
self.initAutoSave = function initAutoSave(saveMethod, duration) {
timer_sleep = duration;
saveFunction = function saveFunction() {
if (saveMethod) {
saveMethod();
}
}
saveTimer = window.setTimeout(saveFunction, timer_sleep);
}
self.resetAutoSave = function resetAutoSave() {
window.clearTimeout(saveTimer);
saveTimer = window.setTimeout(saveFunction, timer_sleep);
}
return self;
});
The module above is used to setup an autosave method. What I have noticed is that initially the method is called. Later however when I call reset the method is no longer called.
I have spent some time researching this and can find no reason why a setTimeout would suddenly cease to fire after having the timer cleared and reset.
Thanks in advance for any help!
I discovered the reason for this is due to the fact that the function needs to be passed into the reset so when the timer is reinitialized it can have a reference to the function like so:
self.resetAutoSave = function resetAutoSave(saveMethod) {
window.clearTimeout(saveTimer);
saveTimer = null;
saveFunction = null;
saveFunction = function saveFunction() {
if (saveMethod) {
saveMethod();
}
}
saveTimer = window.setTimeout(saveFunction, timer_sleep);
}
I was messing around with IndexedDB and I realised that I don't really get event handling in JavaScript.
So here's the code:
var request = indexeddb.open(bla, version);
request.onsuccess = function (event) { };
So the open-method returns a IDBOpenDBRequest object, which, according to Mozillas site, inherits from IDBRequest, which apart from properties and methods also has event handlers, one of them being onsuccess:
https://developer.mozilla.org/en-US/docs/Web/API/IDBRequest.onsuccess
So on the mozilla site, onsuccess is just function () { }
Now, when the database was opened sucessfully, the "onsuccess" event fires and the appropiate event handler is called, in this case the function that I defined. But how exactly does that happen?
The request variable contains an instance of the IDBOpenDBRequest. So when I write request.onsuccess = somefunction(), am I overwriting the default function of the IDBRequest-class?
I dont get why I can write request.onsuccess = somefunction(event) { } and how the event is passed to that function.
EDIT:
function myObect() {
this.open = function(a,b,c) {
if (c > 20) {
this.success("String");
}
};
};
var myrequest = new myObect();
myrequest.open(4,2,21);
myrequest.success = function (ev) {
console.log(ev);
};
To create a similar api, you can do something like:
function open(a, b, c) {
var request = {};
if(c > 20) {
setTimeout(function() {
if(typeof request.success === "function") {
request.success("String");
}
}, 1);
}
return request;
}
var myrequest = open(4, 2, 21);
myrequest.success = function(ev) {
console.log(ev);
};
Here, setTimeout is asynchronous so the callback function is not executed immediately. When any asynchronous task is run in JavaScript, the currently executing code will run to completion before any callback is called. So success is guaranteed to be set before request.success called.
The Indexed DB open call similarly runs an asynchronous task, and then dispatches events when it is finished which will eventually call your callback function.
I overwriting the default function of the IDBRequest-class
Looks like there is no default behavior, so you just set up your own func.