JavaScript ajax library critique

T

Thomas 'PointedEars' Lahn

Garrett said:
Thomas said:
David said:
Garrett Smith wrote:
David Mark wrote:
Mychal Hackman wrote:
[...]
Will leak memory in IE too. You need to set onreadystatechange to an
empty function when done.
(Such as Function.prototype)
That's an interesting idea. I've always used an empty function.

There is also a subtle difference between ES3F and ES5 that challenges
whether using `Function.prototype' here is still a viable approach:
[...]

Note that the part about the empty body is gone from ES5 which means that
a ES5-conforming implementation could actually do something when this
method is called as long as it accepts any arguments and returns
`undefined'.

So what? They removed the obvious.
Nonsense.

A legal implementation extension might be to add behavior to
Function.prototype that causes system side effects.

Which it why it should not be used anymore.
The same is true for any built-in function (parseInt, etc).

You don't know what you are talking about.


PointedEars
 
D

David Mark

David said:
David Mark wrote:
David Mark wrote:
Mychal Hackman wrote:
[...]
[...]



No, you are just confusing the uninitiated with your confusion.

You wrote:

| Ajax is global.  It's not referenced by the local Activation
| Object.  If it were, virtually everything would leak (think about it)..

The Ajax object is not a member of the containing scope, but it is a
member of an object in the containing scope's containing scope.

Which is irrelevant for our purposes. You are missing the obvious.
So rather than xhr -> onreadystatechange function [[Scope]] -> function
[[Scope]] -> xhr, we have:

xhr -> onreadystatechange function [[Scope]] -> Ajax.Request function
[[Scope]] --> global [[Scope]].

Nope. Not a circular reference.

Think about what you quoted above. _Everything_ would leak if
affected implementations were foolish enough to maintain links to the
Global Object for every object. They obviously have no need to do
that and they don't do it, so it doesn't matter.

http://www.jibbering.com/faq/faq_notes/closures.html#clMem
 
G

Garrett Smith

Thomas said:
Garrett said:
Thomas said:
David Mark wrote:
Garrett Smith wrote:
David Mark wrote:
Mychal Hackman wrote:
[...]
Will leak memory in IE too. You need to set onreadystatechange to an
empty function when done.
(Such as Function.prototype)
That's an interesting idea. I've always used an empty function.
There is also a subtle difference between ES3F and ES5 that challenges
whether using `Function.prototype' here is still a viable approach: [...]

Note that the part about the empty body is gone from ES5 which means that
a ES5-conforming implementation could actually do something when this
method is called as long as it accepts any arguments and returns
`undefined'.
So what? They removed the obvious.

Nonsense.

What is nonsense? And why?
Which it why it should not be used anymore.


You don't know what you are talking about.

Do you have a reason for believing that, or is it more hot air?
 
G

Garrett Smith

David said:
David said:
David Mark wrote:
David Mark wrote:
Mychal Hackman wrote:
[...] [...]



No, you are just confusing the uninitiated with your confusion.
You wrote:

| Ajax is global. It's not referenced by the local Activation
| Object. If it were, virtually everything would leak (think about it).

The Ajax object is not a member of the containing scope, but it is a
member of an object in the containing scope's containing scope.

Which is irrelevant for our purposes. You are missing the obvious.
So rather than xhr -> onreadystatechange function [[Scope]] -> function
[[Scope]] -> xhr, we have:

xhr -> onreadystatechange function [[Scope]] -> Ajax.Request function
[[Scope]] --> global [[Scope]].

Nope. Not a circular reference.

Think about what you quoted above. _Everything_ would leak if
affected implementations were foolish enough to maintain links to the
Global Object for every object. They obviously have no need to do
that and they don't do it, so it doesn't matter.

The global scope object is on the scope chain.

Suppose the entire object were not global, but hidden.

(function(){

var Ajax = {
transport : function(){
if(window.XMLHttpRequest){
return new XMLHttpRequest();
}else if(window.ActiveXObject){
return new ActiveXObject('Microsoft.XMLHTTP');
}else{
return false;
}
})(),

Request : function(url, params, onsuccess, method){
var xhr = Ajax.transport,
res = '',
post = null;

xhr.onreadystatechange = function(){
if(onsuccess && xhr.readyState==4){
res = xhr.responseText ||
xhr.responseJSON ||
xhr.responseXML;

onsuccess(res);
}
};
//...
}
}

Now suppose for a second that a local identifer xhr had *not* been used,
but instead, that Ajax.transport had been used. Would there be a
circular reference?

Request : function(url, params, onsuccess, method){
var res = '',
post = null;

Ajax.transport.onreadystatechange = function(){
if(onsuccess && xhr.readyState==4){
res = xhr.responseText ||
xhr.responseJSON ||
xhr.responseXML;

onsuccess(res);
}
};
// ...

Good:
| A circular reference is when two or more objects refer to each other
| in a way that can be followed and lead back to the starting point.

Is there a circular reference in the above example?

Ajax.transport -> XHR_OBJECT -> onreadystatechange -> function[[Scope]]
- > function[[scope]] -> Ajax.transport.

As long as Ajax.transport exists on the scope chain, it can't be collected.

The Ajax object itself could be collected, so long as there were no
other references to it. The transport property would be collectible too,
but that has a reference and that reference is a Host object. Now that
host object has a property onreadystatechange, which points to a
function, and that function has a scope chain, that scope chain has, at
the end, a member object with the member Ajax.
 
D

David Mark

David said:
David Mark wrote:
David Mark wrote:
David Mark wrote:
Mychal Hackman wrote:
[...]
[...]
No, you are just confusing the uninitiated with your confusion.
You wrote:
| Ajax is global.  It's not referenced by the local Activation
| Object.  If it were, virtually everything would leak (think about it).
The Ajax object is not a member of the containing scope, but it is a
member of an object in the containing scope's containing scope.
Which is irrelevant for our purposes.  You are missing the obvious.
So rather than xhr -> onreadystatechange function [[Scope]] -> function
[[Scope]] -> xhr, we have:
xhr -> onreadystatechange function [[Scope]] -> Ajax.Request function
[[Scope]] --> global [[Scope]].
Nope.  Not a circular reference.
Think about what you quoted above.  _Everything_ would leak if
affected implementations were foolish enough to maintain links to the
Global Object for every object.  They obviously have no need to do
that and they don't do it, so it doesn't matter.

The global scope object is on the scope chain.

Suppose the entire object were not global, but hidden.

(function(){

That's obviously different. As with the viewport discussion (and
attributes before that) you've latched on to the wrong end of the
stick and are beating the thread to death with it. :(
 
G

Garrett Smith

Asen said:
David said:
Yes. There are lots of examples (e.g. all ActiveX methods):-

No. From that i can see they have own implementation of internal
[[Get]] and [[Put]] methods.

var a = window.external.addFavorite;

No type conversion but error is still there. Interesting in that part
is typeof.

[...]

The error is unrelated to type conversion. The typeof operator works on
reference and so it seems that typeof can't get a reference, then it
returns "unknown".
 
J

JR

Do you keep a running list of host objects that do?  It's best to
avoid the issue.

Wise advice. Thanks.

I suggest checking for that in the first place, because IE is *still*
the most used browser (I hat to admit that). For instance:
var getXhr = (function() {
  var activeXmodes = ["Msxml2.XMLHTTP", "Microsoft.XMLHTTP"];
  if (window.ActiveXObject) {
No.  IE has supported XMLHttpRequest since version 7
Ok, I forgot that IE's native XMLHTTP support is enabled by default.
But anyone can disable it, so...

You need to use a try-catch with it as well.
Anyway, if even MS checks for the
native object as a first step, I won't be the 'smart alec' here saying
the contrary:
Huh?



http://msdn.microsoft.com/en-us/library/ms537505(VS.85).aspx

What is it you see there?

I see the following text [excerpt]:

"XMLHTTP in IE7 vs. IE6
The native implementation of the XMLHTTP object is designed with cross-
browser compatibility in mind. With just a bit of script, it is easy
to build a function that works with either version of Internet
Explorer, or any browser that supports XMLHTTP. See XMLHttpRequest for
complete documentation and examples.

var xmlHttp = null;
if (window.XMLHttpRequest) {
// If IE7, Mozilla, Safari, and so on: Use native object.
xmlHttp = new XMLHttpRequest();
}
else
{
if (window.ActiveXObject) {
// ...otherwise, use the ActiveX control for IE5.x and IE6.
xmlHttp = new ActiveXObject('MSXML2.XMLHTTP.3.0');
}
}

Internet Explorer 7 supports the legacy implementation of XMLHTTP in
addition to the new native object, so pages currently using the
ActiveX control do not have to be rewritten. However, it is more
efficient to create a native scriptable object than to create an
ActiveX object. This is especially beneficial to those AJAX
applications that create a new XMLHTTP object for each request.

The native object also supports the use of expandos (custom
properties), and properly recognizes the 'this' notation of
Javascript.

ActiveX vs. XMLHTTP
Users and organizations that choose to disallow ActiveX controls can
still use XMLHTTP-based Web applications in Internet Explorer 7.
However, native XMLHTTP support can be disabled from the Advanced
settings tab of the Internet Options dialog box.

Internet Options Dialog
Clients can configure their own policy and simultaneously retain
functionality across key AJAX scenarios. By default, the native
implementation of XMLHTTP is enabled for all MSHTML hosts; however,
individual host applications can choose to disable XMLHTTP with the
FEATURE_XMLHTTP feature control key. An organization can use Group
Policy to disable XMLHTTP for all users of its network.

If native XMLHTTP has been disabled, developers can override the
XMLHttpRequest property of the window object with the MSXML-XMLHTTP
control, unless ActiveX has also been disabled, as in the following
example.

if (!window.XMLHttpRequest) {
window.XMLHttpRequest = function() {
try {
return new ActiveXObject('MSXML2.XMLHTTP.3.0');
}
catch (ex) {
return null;
}
}
}
"

[...] some users have
ActiveX disabled for them and some agents have dummy global
ActiveXObject properties to prevent unnecessary exclusion by browser
sniffing scripts.
I didn't follow what's the problem?

Some agents implement window.ActiveXObject, but it doesn't do anything.

Thanks for that!

Cheers,
JR
 
D

David Mark

Do you keep a running list of host objects that do?  It's best to
avoid the issue.

Wise advice. Thanks.


I suggest checking for that in the first place, because IE is *still*
the most used browser (I hat to admit that). For instance:
var getXhr = (function() {
  var activeXmodes = ["Msxml2.XMLHTTP", "Microsoft.XMLHTTP"];
  if (window.ActiveXObject) {
No.  IE has supported XMLHttpRequest since version 7
Ok, I forgot that IE's native XMLHTTP support is enabled by default.
But anyone can disable it, so...
You need to use a try-catch with it as well.

What is it you see there?

I see the following text [excerpt]:

"XMLHTTP in IE7 vs. IE6
The native implementation of the XMLHTTP object is designed with cross-
browser compatibility in mind. With just a bit of script, it is easy
to build a function that works with either version of Internet
Explorer, or any browser that supports XMLHTTP. See XMLHttpRequest for
complete documentation and examples.

var xmlHttp = null;
if (window.XMLHttpRequest) {

So, they don't know how to detect their own hosts' features.
  // If IE7, Mozilla, Safari, and so on: Use native object.
  xmlHttp = new XMLHttpRequest();}

else
{
  if (window.ActiveXObject) {

And so on.
     // ...otherwise, use the ActiveX control for IE5.x and IE6.
     xmlHttp = new ActiveXObject('MSXML2.XMLHTTP.3.0');

No try-catch either. :)
  }

}

Internet Explorer 7 supports the legacy implementation of XMLHTTP in
addition to the new native object, so pages currently using the
ActiveX control do not have to be rewritten. However, it is more
efficient to create a native scriptable object than to create an
ActiveX object. This is especially beneficial to those AJAX
applications that create a new XMLHTTP object for each request.

Yes. Lot of those. :(
The native object also supports the use of expandos (custom
properties), and properly recognizes the 'this' notation of
Javascript.

ActiveX vs. XMLHTTP
Users and organizations that choose to disallow ActiveX controls can
still use XMLHTTP-based Web applications in Internet Explorer 7.
Yes.

However, native XMLHTTP support can be disabled from the Advanced
settings tab of the Internet Options dialog box.
Yes.

[...]


If native XMLHTTP has been disabled, developers can override the
XMLHttpRequest property of the window object with the MSXML-XMLHTTP
control, unless ActiveX has also been disabled, as in the following
example.

if (!window.XMLHttpRequest) {
    window.XMLHttpRequest = function() {
        try {
            return new ActiveXObject('MSXML2.XMLHTTP.3.0');
        }
        catch (ex) {
            return null;
        }
    }}

Awful.
 
G

Garrett Smith

David said:
David said:
David Mark wrote:
David Mark wrote:
David Mark wrote:
Mychal Hackman wrote:
[...]
[...]
No, you are just confusing the uninitiated with your confusion.
You wrote:
| Ajax is global. It's not referenced by the local Activation
| Object. If it were, virtually everything would leak (think about it).
The Ajax object is not a member of the containing scope, but it is a
member of an object in the containing scope's containing scope.
Which is irrelevant for our purposes. You are missing the obvious.
So rather than xhr -> onreadystatechange function [[Scope]] -> function
[[Scope]] -> xhr, we have:
xhr -> onreadystatechange function [[Scope]] -> Ajax.Request function
[[Scope]] --> global [[Scope]].
Nope. Not a circular reference.
Think about what you quoted above. _Everything_ would leak if
affected implementations were foolish enough to maintain links to the
Global Object for every object. They obviously have no need to do
that and they don't do it, so it doesn't matter.
The global scope object is on the scope chain.

Suppose the entire object were not global, but hidden.

(function(){

That's obviously different.

Is it a difference that would create a memory leak?

If so, can you explain how?
 
D

David Mark

David said:
David Mark wrote:
David Mark wrote:
David Mark wrote:
David Mark wrote:
Mychal Hackman wrote:
[...]
[...]
No, you are just confusing the uninitiated with your confusion.
You wrote:
| Ajax is global.  It's not referenced by the local Activation
| Object.  If it were, virtually everything would leak (think about it).
The Ajax object is not a member of the containing scope, but it is a
member of an object in the containing scope's containing scope.
Which is irrelevant for our purposes.  You are missing the obvious.
So rather than xhr -> onreadystatechange function [[Scope]] -> function
[[Scope]] -> xhr, we have:
xhr -> onreadystatechange function [[Scope]] -> Ajax.Request function
[[Scope]] --> global [[Scope]].
Nope.  Not a circular reference.
Think about what you quoted above.  _Everything_ would leak if
affected implementations were foolish enough to maintain links to the
Global Object for every object.  They obviously have no need to do
that and they don't do it, so it doesn't matter.
The global scope object is on the scope chain.
Suppose the entire object were not global, but hidden.
(function(){
That's obviously different.  

Is it a difference that would create a memory leak?

If so, can you explain how?

You are going around in circles. :)

http://www.jibbering.com/faq/faq_notes/closures.html#clMem

I already diagrammed the OP's case (as I've done for a thousand
similar cases in the last few years). It's the same diagram for your
latest example. Your previous example had no such (valid) diagram.
 
A

Asen Bozhilov

Garrett said:
David Mark wrote:

You wrote:

| Ajax is global.  It's not referenced by the local Activation
| Object.  If it were, virtually everything would leak (think about it)..

The Ajax object is not a member of the containing scope, but it is a
member of an object in the containing scope's containing scope.

If you are correct:

window.onload = function(){};

That will be produce circular reference. If `window' host object is
property of Global Object diagram is:

Global Object -> window -> onload -> AF[[scope]] -> Global Object
 
D

David Mark

You wrote:
| Ajax is global.  It's not referenced by the local Activation
| Object.  If it were, virtually everything would leak (think about it).
The Ajax object is not a member of the containing scope, but it is a
member of an object in the containing scope's containing scope.

If you are correct:

window.onload = function(){};

That will be produce circular reference. If `window' host object is
property of Global Object diagram is:

Global Object -> window -> onload -> AF[[scope]] -> Global Object

And that's just the tip of the (hypothetical) iceberg. Think about
what other host objects are in the Global scope.

So the hypothesis (which is not new) is obviously bunk.
 
G

Garrett Smith

David said:
David said:
David Mark wrote:
David Mark wrote:
David Mark wrote:
David Mark wrote:
Mychal Hackman wrote:
[...]
[...]
Is it a difference that would create a memory leak?

If so, can you explain how?

You are going around in circles. :)
Either you can explain the difference or you cannot. So far, you have
not been able to explain the difference.
http://www.jibbering.com/faq/faq_notes/closures.html#clMem

I already diagrammed the OP's case (as I've done for a thousand
similar cases in the last few years). It's the same diagram for your
latest example. Your previous example had no such (valid) diagram.

A diagram does not need use the same notation that you used to be valid
and it is indeed valid, just not apparently understandable by you.
 
D

David Mark

David said:
David Mark wrote:
David Mark wrote:
David Mark wrote:
David Mark wrote:
David Mark wrote:
Mychal Hackman wrote:
[...]

[...]>>> That's obviously different.  
You are going around in circles.  :)

Either you can explain the difference or you cannot. So far, you have
not been able to explain the difference.

Either you didn't understand the explanation(s) or you are trying to
save face (and that ship has sailed). There is a third possibility
that you want me to spoon-feed it to you, but baiting won't make that
happen.
A diagram does not need use the same notation that you used to be valid
and it is indeed valid, just not apparently understandable by you.

Who said anything about notation? Your diagram makes no sense in any
notation (that's the point).

Is anyone else here confused? We've been over these circular
reference patterns ad nauseam, but if this is not an isolated case of
confusion, I guess we can go over it again...
 
G

Garrett Smith

Asen said:
Garrett said:
David Mark wrote:
You wrote:

| Ajax is global. It's not referenced by the local Activation
| Object. If it were, virtually everything would leak (think about it).

The Ajax object is not a member of the containing scope, but it is a
member of an object in the containing scope's containing scope.

If you are correct:

window.onload = function(){};

That will be produce circular reference. If `window' host object is
property of Global Object diagram is:

Global Object -> window -> onload -> AF[[scope]] -> Global Object

Right.

In IE, the global variable object is implemented as a JScript object,
and the global object is implemented by the host. That is a bug of IE,
explained in Eric Lippert's blog entry many years ago.

// IE global obj.
Ajax = { ... }

// Global variable obj.
var Ajax = { ... }

COM_OBJECT -> JSCRIPT_OBJ_CHAIN -> COM_OBJ

The global object has to have some sort of tear down to remove break the
chain, as above, so that afte page tear down, there would be:

GLOBAL_COM_OBJ -|| JSCRIPT_OBJ_CHAIN -> COM_OBJ -|| GLOBAL_COM_OBJ

"-||" means chain broken.

And the same for the global variable object:

GLOBAL_SCOPE_OBJECT -|| JSCRIPT_OBJ_CHAIN -> COM_OBJ ->
JSCRIPT_SCOPE_CHAIN -|| GLOBAL_SCOPE_OBJECT

A leak won't occur unless the chain is broken. If the chain is broken
automatically for global object and global variable object then that
leak won't occur.

Someone from Microsoft could probably explain how IE implements page
tear down.

[1]http://blogs.msdn.com/ericlippert/archive/2005/05/04/414684.aspx
 
G

Garrett Smith

David said:
Asen said:
Garrett Smith wrote:
David Mark wrote:
No, you are just confusing the uninitiated with your confusion.
You wrote:
| Ajax is global. It's not referenced by the local Activation
| Object. If it were, virtually everything would leak (think about it).
The Ajax object is not a member of the containing scope, but it is a
member of an object in the containing scope's containing scope.
If you are correct:
window.onload = function(){};
That will be produce circular reference. If `window' host object is
property of Global Object diagram is:
Global Object -> window -> onload -> AF[[scope]] -> Global Object
Right.

Wrong, no leak. Give it up.

It must be frustrating not being able to explain things.
 
T

Thomas 'PointedEars' Lahn

David said:
Yes. Lot of those. :(

While it might be more efficient to use the new "native object" (it isn't
one) over the ActiveX object, it is less helpful, and not suited for a
general-purpose XHR library: by contrast, it does not support `file://' URIs
and it is not backwards-compatible.


PointedEars
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,705
Latest member
Stefkari24

Latest Threads

Top