By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
464,799 Members | 1,316 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 464,799 IT Pros & Developers. It's quick & easy.

IE events expire (typeof = unknown) after callStack finishes. (featuring: setTimeout scoping)

P: n/a
I wrote a pair of functions to enable scoped or referenced setTimeout
calls. I did this because I have an object factory that creates
multiple objects and those objects need to delay a few calls on
themselves at a certain point in time.

This code works fine for normal objects. However, my issue occurs if
at any point, an event object is passed across in IE.

It seems, that events methods and variables in IE are PRIVATE (!)
after the initial callstack has been finished.

The following is the code required to view this bug(?) in IE, and
success in FF.

<html>
<head>
<script>
/*****************************************
Here is the code for the delaying:
******************************************/
// Global variables.
var delayObjects = {}; // Hold the object references.
var delayObjectsIndex = 0; // Keep track of the index.

function delayObjectMethodCall(obj,exp,ms){
delayObjectsIndex++;
delayObjects[delayObjectsIndex] = obj; // This assigns
by reference.

// This is the eval that is to be run.
expNew = '\
if(delayObjects['+delayObjectsIndex+']){\
with(delayObjects['+delayObjectsIndex+']){\
'+exp+';\
}\
delayObjects['+delayObjectsIndex+'] =
undefined}\
';
document.getElementById('result').innerHTML = 'Delay
was called: (event.keyCode = '+obj.event.keyCode+')<br/
>'+document.getElementById('result').innerHTML;
setTimeout(expNew, ms);
return delayObjectsIndex;
}
function delayObjectMethodCallCancel(id){
if(typeof id != 'undefined' && delayObjects[id]){
clearTimeout(id);
delayObjects[id] = undefined;
return true;
}
}
/*********************************************
* Onload

********************************************/
window.onload = function(){
document.getElementById('test').onkeydown=function (e){
if(!e){e=window.event;}
document.getElementById('result').innerHTML =
'Event was fired: (event.keyCode = '+e.keyCode+')<br/
>'+document.getElementById('result').innerHTML;
document.getElementById('result').innerHTML =
'Before Delay: Input Value: '+this.value + '<br/
>'+document.getElementById('result').innerHTML;
// This is the call
delayObjectMethodCall(
// Object To pass
{input:this,event:e,other:'staticObject'},
// String to eval
"\

document.getElementById('result').innerHTML = 'START OF DELAY
PAYLOAD<br/>'+document.getElementById('result').innerHTML;\

document.getElementById('result').innerHTML = 'After Delay: Input
Value: '+input.value + '<br/
>'+document.getElementById('result').innerHTML;\
document.getElementById('result').innerHTML = 'After Delay: Other
Value: '+other + '<br/>'+document.getElementById('result').innerHTML;\
try{\

document.getElementById('result').innerHTML = 'Event keyCode:
'+event.keyCode + '<br/>'+document.getElementById('result').innerHTML;
\
}catch(e){\

document.getElementById('result').innerHTML = '<span style=\"color:red
\">Error:</span'+e.message + '<br/
>'+document.getElementById('result').innerHTML;\
document.getElementById('result').innerHTML = '<span style=\"color:red
\">Error:</spantypeof event: '+typeof event+'<br/
>'+document.getElementById('result').innerHTML;\
document.getElementById('result').innerHTML = '<span style=\"color:red
\">Error:</spantypeof event.keyCode: '+typeof event.keyCode+'<br/
>'+document.getElementById('result').innerHTML;\
}\

document.getElementById('result').innerHTML = 'END OF DELAY PAYLOAD<br/
><br/>'+document.getElementById('result').innerHTML;\
",
100
);
return true;
}
}
</script>
</head>
<body>
<input id="test" type="text" value="change this somehow"/>
<input type="button" value="clear"
onclick="document.getElementById('result').innerHT ML = '';"/>
<div id="result"></div>
</body>
</html>

Feb 20 '07 #1
Share this Question
Share on Google+
3 Replies

P: n/a
On Feb 20, 12:45 pm, pho...@gmail.com wrote:
I wrote a pair of functions to enable scoped or referenced setTimeout
calls. I did this because I have an object factory that creates
multiple objects and those objects need to delay a few calls on
themselves at a certain point in time.

This code works fine for normal objects. However, my issue occurs if
at any point, an event object is passed across in IE.

It seems, that events methods and variables in IE are PRIVATE (!)
after the initial callstack has been finished.

The following is the code required to view this bug(?) in IE, and
success in FF.

<html>
<head>
<script>
/*****************************************
Here is the code for the delaying:
******************************************/
// Global variables.
var delayObjects = {}; // Hold the object references.
var delayObjectsIndex = 0; // Keep track of the index.

function delayObjectMethodCall(obj,exp,ms){
delayObjectsIndex++;
delayObjects[delayObjectsIndex] = obj; // This assigns
by reference.

// This is the eval that is to be run.
expNew = '\
if(delayObjects['+delayObjectsIndex+']){\
with(delayObjects['+delayObjectsIndex+']){\
'+exp+';\
}\
delayObjects['+delayObjectsIndex+'] =
undefined}\
';
document.getElementById('result').innerHTML = 'Delay
was called: (event.keyCode = '+obj.event.keyCode+')<br/>'+document.getElementById('result').innerHTML;

setTimeout(expNew, ms);
return delayObjectsIndex;
}
function delayObjectMethodCallCancel(id){
if(typeof id != 'undefined' && delayObjects[id]){
clearTimeout(id);
delayObjects[id] = undefined;
return true;
}
}

/*********************************************
* Onload

********************************************/
window.onload = function(){
document.getElementById('test').onkeydown=function (e){
if(!e){e=window.event;}
document.getElementById('result').innerHTML =
'Event was fired: (event.keyCode = '+e.keyCode+')<br/>'+document.getElementById('result').innerHTML;

document.getElementById('result').innerHTML =
'Before Delay: Input Value: '+this.value + '<br/>'+document.getElementById('result').innerHTML;

// This is the call
delayObjectMethodCall(
// Object To pass
{input:this,event:e,other:'staticObject'},
// String to eval
"\

document.getElementById('result').innerHTML = 'START OF DELAY
PAYLOAD<br/>'+document.getElementById('result').innerHTML;\

document.getElementById('result').innerHTML = 'After Delay: Input
Value: '+input.value + '<br/
'+document.getElementById('result').innerHTML;\

document.getElementById('result').innerHTML = 'After Delay: Other
Value: '+other + '<br/>'+document.getElementById('result').innerHTML;\
try{\

document.getElementById('result').innerHTML = 'Event keyCode:
'+event.keyCode + '<br/>'+document.getElementById('result').innerHTML;
\
}catch(e){\

document.getElementById('result').innerHTML = '<span style=\"color:red
\">Error:</span'+e.message + '<br/
'+document.getElementById('result').innerHTML;\

document.getElementById('result').innerHTML = '<span style=\"color:red
\">Error:</spantypeof event: '+typeof event+'<br/
'+document.getElementById('result').innerHTML;\

document.getElementById('result').innerHTML = '<span style=\"color:red
\">Error:</spantypeof event.keyCode: '+typeof event.keyCode+'<br/>'+document.getElementById('result').innerHTML;\

}\

document.getElementById('result').innerHTML = 'END OF DELAY PAYLOAD<br/><br/>'+document.getElementById('result').innerHTML;\

",
100
);
return true;
}
}
</script>
</head>
<body>
<input id="test" type="text" value="change this somehow"/>
<input type="button" value="clear"
onclick="document.getElementById('result').innerHT ML = '';"/>
<div id="result"></div>
</body>
</html>
When you look at your code and you see a lot of repetition, even
visually, that's a clue that you should re-examine your style (Don't
Repeat Yourself - Especially When Asking Other People To Look At Your
Code).

1. Try to come up with a way to do this without using "eval". (Hint:
take a look at function closures.) See:
http://jibbering.com/faq/#FAQ4_40
http://javascript.crockford.com/code.html (end).
2. Since the main element you're working with is 'result', why not
just assign it to a variable and avoid the repeated
"document.getElementById" for readability. Ditto with the ubiquitous
multi-line strings (which will go away after you take care of #1).

As for your "event" object problem, the "event" object's properties
are not "private", a concept which does not exist in JavaScript, at
least not in any way analogous to C++ or Java. The problem here, as
your example demonstrates, is as follows: after the called event
handler exits and its scope chain is broken down, the window.event
object is cleared for the next event and any references to it are no
longer valid. You should instead pass in any specific values (such as
keyCode) to your literal, as these will be preserved across the
boundary.

-David
Feb 21 '07 #2

P: n/a
On Feb 20, 9:06 pm, "David Golightly" <davig...@gmail.comwrote:
On Feb 20, 12:45 pm, pho...@gmail.com wrote:
I wrote a pair of functions to enable scoped or referenced setTimeout
calls. I did this because I have an object factory that creates
multiple objects and those objects need to delay a few calls on
themselves at a certain point in time.
This code works fine for normal objects. However, my issue occurs if
at any point, an event object is passed across inIE.
It seems, thateventsmethods and variables inIEare PRIVATE (!)
after the initial callstack has been finished.
The following is the code required to view this bug(?) inIE, and
success in FF.
<html>
<head>
<script>
/*****************************************
Here is the code for the delaying:
******************************************/
// Global variables.
var delayObjects = {}; // Hold the object references.
var delayObjectsIndex = 0; // Keep track of the index.
function delayObjectMethodCall(obj,exp,ms){
delayObjectsIndex++;
delayObjects[delayObjectsIndex] = obj; // This assigns
by reference.
// This is the eval that is to be run.
expNew = '\
if(delayObjects['+delayObjectsIndex+']){\
with(delayObjects['+delayObjectsIndex+']){\
'+exp+';\
}\
delayObjects['+delayObjectsIndex+'] =
undefined}\
';
document.getElementById('result').innerHTML = 'Delay
was called: (event.keyCode = '+obj.event.keyCode+')<br/>'+document.getElementById('result').innerHTML;
setTimeout(expNew, ms);
return delayObjectsIndex;
}
function delayObjectMethodCallCancel(id){
if(typeof id != 'undefined' && delayObjects[id]){
clearTimeout(id);
delayObjects[id] = undefined;
return true;
}
}
/*********************************************
* Onload
********************************************/
window.onload = function(){
document.getElementById('test').onkeydown=function (e){
if(!e){e=window.event;}
document.getElementById('result').innerHTML =
'Event was fired: (event.keyCode = '+e.keyCode+')<br/>'+document.getElementById('result').innerHTML;
document.getElementById('result').innerHTML =
'Before Delay: Input Value: '+this.value + '<br/>'+document.getElementById('result').innerHTML;
// This is the call
delayObjectMethodCall(
// Object To pass
{input:this,event:e,other:'staticObject'},
// String to eval
"\
document.getElementById('result').innerHTML = 'START OF DELAY
PAYLOAD<br/>'+document.getElementById('result').innerHTML;\
document.getElementById('result').innerHTML = 'After Delay: Input
Value: '+input.value + '<br/
>'+document.getElementById('result').innerHTML;\
document.getElementById('result').innerHTML = 'After Delay: Other
Value: '+other + '<br/>'+document.getElementById('result').innerHTML;\
try{\
document.getElementById('result').innerHTML = 'Event keyCode:
'+event.keyCode + '<br/>'+document.getElementById('result').innerHTML;
\
}catch(e){\
document.getElementById('result').innerHTML = '<span style=\"color:red
\">Error:</span'+e.message + '<br/
>'+document.getElementById('result').innerHTML;\
document.getElementById('result').innerHTML = '<span style=\"color:red
\">Error:</spantypeof event: '+typeof event+'<br/
>'+document.getElementById('result').innerHTML;\
document.getElementById('result').innerHTML = '<span style=\"color:red
\">Error:</spantypeof event.keyCode: '+typeof event.keyCode+'<br/>'+document.getElementById('result').innerHTML;\
}\
document.getElementById('result').innerHTML = 'END OF DELAY PAYLOAD<br/><br/>'+document.getElementById('result').innerHTML;\
",
100
);
return true;
}
}
</script>
</head>
<body>
<input id="test" type="text" value="change this somehow"/>
<input type="button" value="clear"
onclick="document.getElementById('result').innerHT ML = '';"/>
<div id="result"></div>
</body>
</html>

When you look at your code and you see a lot of repetition, even
visually, that's a clue that you should re-examine your style (Don't
Repeat Yourself - Especially When Asking Other People To Look At Your
Code).

1. Try to come up with a way to do this without using "eval". (Hint:
take a look at function closures.) See:http://jibbering.com/faq/#FAQ4_40htt...code.html(end).
2. Since the main element you're working with is 'result', why not
just assign it to a variable and avoid the repeated
"document.getElementById" for readability. Ditto with the ubiquitous
multi-line strings (which will go away after you take care of #1).

As for your "event" object problem, the "event" object's properties
are not "private", a concept which does not exist in JavaScript, at
least not in any way analogous to C++ or Java. The problem here, as
your example demonstrates, is as follows: after the called event
handler exits and its scope chain is broken down, the window.event
object is cleared for the next event and any references to it are no
longer valid. You should instead pass in any specific values (such as
keyCode) to your literal, as these will be preserved across the
boundary.

-David
In response to your first point:
Closures will not work for what I'm trying to accomplish. The only way
to process a delayed execution is with either eval or setTimeout. I
cannot imagine that there is any other obvious way to do it. And what
I was trying to share was that it is possible to pass object
references with it using my two functions.

In response to your second point:
All of the repetition is for the display of the testing logic.
Granted, I guess it's still bad to have, but I wanted things to be as
straight forward as possible. As that was my first post to a
newsgroup, I was unaware that my message would be formatted to a set
column size. I apologize for the resulting obfuscation.

Feb 21 '07 #3

P: n/a
On Feb 21, 2:28 pm, pho...@gmail.com wrote:
On Feb 20, 9:06 pm, "David Golightly" <davig...@gmail.comwrote:
On Feb 20, 12:45 pm, pho...@gmail.com wrote:
I wrote a pair of functions to enable scoped or referenced setTimeout
calls. I did this because I have an object factory that creates
multiple objects and those objects need to delay a few calls on
themselves at a certain point in time.
This code works fine for normal objects. However, my issue occurs if
at any point, an event object is passed across inIE.
It seems, thateventsmethods and variables inIEare PRIVATE (!)
after the initial callstack has been finished.
The following is the code required to view this bug(?) inIE, and
success in FF.
<html>
<head>
<script>
/*****************************************
Here is the code for the delaying:
******************************************/
// Global variables.
var delayObjects = {}; // Hold the object references.
var delayObjectsIndex = 0; // Keep track of the index.
function delayObjectMethodCall(obj,exp,ms){
delayObjectsIndex++;
delayObjects[delayObjectsIndex] = obj; // This assigns
by reference.
// This is the eval that is to be run.
expNew = '\
if(delayObjects['+delayObjectsIndex+']){\
with(delayObjects['+delayObjectsIndex+']){\
'+exp+';\
}\
delayObjects['+delayObjectsIndex+'] =
undefined}\
';
document.getElementById('result').innerHTML = 'Delay
was called: (event.keyCode = '+obj.event.keyCode+')<br/>'+document.getElementById('result').innerHTML;
setTimeout(expNew, ms);
return delayObjectsIndex;
}
function delayObjectMethodCallCancel(id){
if(typeof id != 'undefined' && delayObjects[id]){
clearTimeout(id);
delayObjects[id] = undefined;
return true;
}
}
/*********************************************
* Onload
********************************************/
window.onload = function(){
document.getElementById('test').onkeydown=function (e){
if(!e){e=window.event;}
document.getElementById('result').innerHTML =
'Event was fired: (event.keyCode = '+e.keyCode+')<br/>'+document.getElementById('result').innerHTML;
document.getElementById('result').innerHTML =
'Before Delay: Input Value: '+this.value + '<br/>'+document.getElementById('result').innerHTML;
// This is the call
delayObjectMethodCall(
// Object To pass
{input:this,event:e,other:'staticObject'},
// String to eval
"\
document.getElementById('result').innerHTML = 'START OF DELAY
PAYLOAD<br/>'+document.getElementById('result').innerHTML;\
document.getElementById('result').innerHTML = 'After Delay: Input
Value: '+input.value + '<br/
'+document.getElementById('result').innerHTML;\
document.getElementById('result').innerHTML = 'After Delay: Other
Value: '+other + '<br/>'+document.getElementById('result').innerHTML;\
try{\
document.getElementById('result').innerHTML = 'Event keyCode:
'+event.keyCode + '<br/>'+document.getElementById('result').innerHTML;
\
}catch(e){\
document.getElementById('result').innerHTML = '<span style=\"color:red
\">Error:</span'+e.message + '<br/
'+document.getElementById('result').innerHTML;\
document.getElementById('result').innerHTML = '<span style=\"color:red
\">Error:</spantypeof event: '+typeof event+'<br/
'+document.getElementById('result').innerHTML;\
document.getElementById('result').innerHTML = '<span style=\"color:red
\">Error:</spantypeof event.keyCode: '+typeof event.keyCode+'<br/>'+document.getElementById('result').innerHTML;\
}\
document.getElementById('result').innerHTML = 'END OF DELAY PAYLOAD<br/><br/>'+document.getElementById('result').innerHTML;\
",
100
);
return true;
}
}
</script>
</head>
<body>
<input id="test" type="text" value="change this somehow"/>
<input type="button" value="clear"
onclick="document.getElementById('result').innerHT ML = '';"/>
<div id="result"></div>
</body>
</html>
When you look at your code and you see a lot of repetition, even
visually, that's a clue that you should re-examine your style (Don't
Repeat Yourself - Especially When Asking Other People To Look At Your
Code).
1. Try to come up with a way to do this without using "eval". (Hint:
take a look at function closures.) See:http://jibbering.com/faq/#FAQ4_40htt...d.com/code...).
2. Since the main element you're working with is 'result', why not
just assign it to a variable and avoid the repeated
"document.getElementById" for readability. Ditto with the ubiquitous
multi-line strings (which will go away after you take care of #1).
As for your "event" object problem, the "event" object's properties
are not "private", a concept which does not exist in JavaScript, at
least not in any way analogous to C++ or Java. The problem here, as
your example demonstrates, is as follows: after the called event
handler exits and its scope chain is broken down, the window.event
object is cleared for the next event and any references to it are no
longer valid. You should instead pass in any specific values (such as
keyCode) to your literal, as these will be preserved across the
boundary.
-David

In response to your first point:
Closures will not work for what I'm trying to accomplish. The only way
to process a delayed execution is with either eval or setTimeout. I
cannot imagine that there is any other obvious way to do it. And what
I was trying to share was that it is possible to pass object
references with it using my two functions.
You don't even need any arrays:

var expNew = function(fn, obj) {
return function() {
if (obj) {
fn.call(obj);
}
}
}

function delayObjectMethodCall(obj, fn, ms) {
setTimeout(expNew(fn, obj), ms);
}

You can probably figure out the rest of your example on that model.
>
In response to your second point:
All of the repetition is for the display of the testing logic.
Granted, I guess it's still bad to have, but I wanted things to be as
straight forward as possible. As that was my first post to a
newsgroup, I was unaware that my message would be formatted to a set
column size. I apologize for the resulting obfuscation.
No worries!

-David

Feb 21 '07 #4

This discussion thread is closed

Replies have been disabled for this discussion.