You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by hs...@apache.org on 2012/07/24 02:40:52 UTC

svn commit: r1364855 - in /shindig/trunk: config/ features/src/main/javascript/features/core.io/ features/src/main/javascript/features/core.util.base/

Author: hsaputra
Date: Tue Jul 24 00:40:52 2012
New Revision: 1364855

URL: http://svn.apache.org/viewvc?rev=1364855&view=rev
Log:
 Fix memory leak in IE7 for Ajax call in core.io feature using polling technique to do the xhr state change handler. CR: https://reviews.apache.org/r/6070/.

Added:
    shindig/trunk/features/src/main/javascript/features/core.util.base/taming.js
Modified:
    shindig/trunk/config/container.js
    shindig/trunk/features/src/main/javascript/features/core.io/io.js
    shindig/trunk/features/src/main/javascript/features/core.util.base/base.js
    shindig/trunk/features/src/main/javascript/features/core.util.base/feature.xml

Modified: shindig/trunk/config/container.js
URL: http://svn.apache.org/viewvc/shindig/trunk/config/container.js?rev=1364855&r1=1364854&r2=1364855&view=diff
==============================================================================
--- shindig/trunk/config/container.js (original)
+++ shindig/trunk/config/container.js Tue Jul 24 00:40:52 2012
@@ -162,7 +162,10 @@
     "unparseableCruft" : "throw 1; < don't be evil' >",
 
     // This variable is needed during the config init to parse config augmentation
-    "jsPath" : "${Cur['gadgets.uri.js.path']}"
+    "jsPath" : "${Cur['gadgets.uri.js.path']}",
+
+    // interval in milliseconds used to poll xhr request for the readyState
+    "xhrPollIntervalMs" : 50
   },
   "views" : {
     "profile" : {

Modified: shindig/trunk/features/src/main/javascript/features/core.io/io.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/core.io/io.js?rev=1364855&r1=1364854&r2=1364855&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/core.io/io.js (original)
+++ shindig/trunk/features/src/main/javascript/features/core.io/io.js Tue Jul 24 00:40:52 2012
@@ -30,6 +30,12 @@
  */
 
 gadgets.io = function() {
+  // Ever incrementing Ajax transaction id
+  var ioTransactionId = 0;
+
+  // Object to store ids for the ajax poll to avoid IE memory leak
+  var ajaxPollQ = {};
+
   /**
    * Holds configuration-related data such as proxy urls.
    */
@@ -259,8 +265,17 @@ gadgets.io = function() {
 
     xhr.open(method, proxyUrl, true);
     if (callback) {
-      xhr.onreadystatechange = gadgets.util.makeClosure(
-          null, processResponseFunction, realUrl, callback, params, xhr);
+      var closureCallback = gadgets.util.makeClosure(null, processResponseFunction, realUrl,
+        callback, params, xhr);
+
+      // check for alternate ajax for onreadystatechange event handler
+      var shouldPoll = gadgets.util.shouldPollXhrReadyStateChange();
+      if(shouldPoll) {
+        handleReadyState(xhr, closureCallback);
+      }
+      else {
+        xhr.onreadystatechange = closureCallback;
+      }
     }
 
     if (typeof opt_headers === 'string') {
@@ -285,6 +300,38 @@ gadgets.io = function() {
   }
 
   /**
+    * Helper function to use poll setInterval to call the callback for Ajax to avoid
+    * memory leak in certain browsers (eg: IE7) due to circular linking.
+    *
+    * The function  will create  interval polling to poll the XHR object's readyState
+    * property instead of binding a callback to the onreadystatechange event.
+    *
+    * @param {xhr} The Ajax object
+    * @param {function} The callback function for the Ajax call
+    * @return void
+    */
+    function handleReadyState(xhr, callback) {
+      var tempTid = ioTransactionId;
+      var pollInterval = config['xhrPollIntervalMs'] || 50;
+      ajaxPollQ[tempTid] = window.setInterval(
+        function() {
+          if(xhr && xhr.readyState === 4) {
+            // Clear the polling interval for the transaction and remove
+            // the reference from ajaxPollQ
+            window.clearInterval(ajaxPollQ[tempTid]);
+            delete ajaxPollQ[tempTid];
+
+            // call the callback
+            if(callback) {
+              callback();
+            }
+          }
+        }, pollInterval);
+
+      ioTransactionId++;
+    }
+
+  /**
    * Satisfy a request with data that is prefetched as per the gadget Preload
    * directive. The preloader will only satisfy a request for a specific piece
    * of content once.

Modified: shindig/trunk/features/src/main/javascript/features/core.util.base/base.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/core.util.base/base.js?rev=1364855&r1=1364854&r2=1364855&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/core.util.base/base.js (original)
+++ shindig/trunk/features/src/main/javascript/features/core.util.base/base.js Tue Jul 24 00:40:52 2012
@@ -75,3 +75,15 @@ gadgets.util.makeEnum = function(values)
   return obj;
 };
 
+/**
+ * Check if need to poll for Ajax ready state change to avoid browsers memory leak.
+ * The default implementation will check for IE7 browsers.
+ *
+ * @return true if we need to add polling to handle ready state change and false otherwise.
+ */
+gadgets.util.shouldPollXhrReadyStateChange = function() {
+  if (document.all && !document.querySelector) {
+    return true;
+  }
+  return false;
+}

Modified: shindig/trunk/features/src/main/javascript/features/core.util.base/feature.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/core.util.base/feature.xml?rev=1364855&r1=1364854&r2=1364855&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/core.util.base/feature.xml (original)
+++ shindig/trunk/features/src/main/javascript/features/core.util.base/feature.xml Tue Jul 24 00:40:52 2012
@@ -21,9 +21,11 @@
   <dependency>globals</dependency>
   <all>
     <script src="base.js"/>
+    <script src="taming.js" caja="1"/>
     <api>
       <exports type="js">gadgets.util.makeClosure</exports>
       <exports type="js">gadgets.util.makeEnum</exports>
+      <exports type="js">gadgets.util.shouldPollXhrReadyStateChange</exports>
     </api>
   </all>
 </feature>

Added: shindig/trunk/features/src/main/javascript/features/core.util.base/taming.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/core.util.base/taming.js?rev=1364855&view=auto
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/core.util.base/taming.js (added)
+++ shindig/trunk/features/src/main/javascript/features/core.util.base/taming.js Tue Jul 24 00:40:52 2012
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * @class
+ * Tame and expose core gadgets.* API to cajoled gadgets
+ */
+tamings___.push(function(imports) {
+  caja___.whitelistFuncs([
+    [gadgets.util, 'makeClosure'],
+    [gadgets.util, 'makeEnum'],
+    [gadgets.util, 'shouldPollXhrReadyStateChange']
+  ]);
+});