]> source.dussan.org Git - vaadin-framework.git/commitdiff
Remove custom preloading support and load scripts using async=false (#8291)
authorArtur <artur@vaadin.com>
Mon, 23 Jan 2017 15:05:01 +0000 (17:05 +0200)
committerDenis <denis@vaadin.com>
Mon, 23 Jan 2017 15:05:01 +0000 (17:05 +0200)
When using async='false' for scripts created by scripts
the execution order is guaranteed to be the same as the order the
script tags are created

Fixes #5339, #3631

client/src/main/java/com/vaadin/client/DependencyLoader.java
client/src/main/java/com/vaadin/client/ResourceLoader.java

index c644cd87dbf24b5a2e0e6fc32be74216563a893c..d217c824b2adb32085baa96c76950f57ef414d26 100644 (file)
@@ -113,12 +113,6 @@ public class DependencyLoader {
         ResourceLoadListener resourceLoadListener = new ResourceLoadListener() {
             @Override
             public void onLoad(ResourceLoadEvent event) {
-                if (dependencies.length() != 0) {
-                    String url = translateVaadinUri(dependencies.shift());
-                    ApplicationConfiguration.startDependencyLoading();
-                    // Load next in chain (hopefully already preloaded)
-                    event.getResourceLoader().loadScript(url, this);
-                }
                 // Call start for next before calling end for current
                 ApplicationConfiguration.endDependencyLoading();
             }
@@ -133,23 +127,10 @@ public class DependencyLoader {
         };
 
         ResourceLoader loader = ResourceLoader.get();
-
-        // Start chain by loading first
-        String url = translateVaadinUri(dependencies.shift());
-        ApplicationConfiguration.startDependencyLoading();
-        loader.loadScript(url, resourceLoadListener);
-
-        if (ResourceLoader.supportsInOrderScriptExecution()) {
-            for (int i = 0; i < dependencies.length(); i++) {
-                String preloadUrl = translateVaadinUri(dependencies.get(i));
-                loader.loadScript(preloadUrl, null);
-            }
-        } else {
-            // Preload all remaining
-            for (int i = 0; i < dependencies.length(); i++) {
-                String preloadUrl = translateVaadinUri(dependencies.get(i));
-                loader.preloadResource(preloadUrl, null);
-            }
+        for (int i = 0; i < dependencies.length(); i++) {
+            ApplicationConfiguration.startDependencyLoading();
+            String preloadUrl = translateVaadinUri(dependencies.get(i));
+            loader.loadScript(preloadUrl, resourceLoadListener);
         }
     }
 
index 37f6f51a4c0e75507c415ffccd29ca92e52533d4..a20daced443f4d2e0814a5a7c5d3e02974e6f437 100644 (file)
@@ -21,6 +21,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.logging.Logger;
 
 import com.google.gwt.core.client.Duration;
 import com.google.gwt.core.client.GWT;
@@ -30,7 +31,6 @@ import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.LinkElement;
 import com.google.gwt.dom.client.NodeList;
-import com.google.gwt.dom.client.ObjectElement;
 import com.google.gwt.dom.client.ScriptElement;
 import com.google.gwt.user.client.Timer;
 
@@ -38,10 +38,6 @@ import com.google.gwt.user.client.Timer;
  * ResourceLoader lets you dynamically include external scripts and styles on
  * the page and lets you know when the resource has been loaded.
  *
- * You can also preload resources, allowing them to get cached by the browser
- * without being evaluated. This enables downloading multiple resources at once
- * while still controlling in which order e.g. scripts are executed.
- *
  * @author Vaadin Ltd
  * @since 7.0.0
  */
@@ -52,7 +48,6 @@ public class ResourceLoader {
     public static class ResourceLoadEvent {
         private final ResourceLoader loader;
         private final String resourceUrl;
-        private final boolean preload;
 
         /**
          * Creates a new event.
@@ -61,19 +56,14 @@ public class ResourceLoader {
          *            the resource loader that has loaded the resource
          * @param resourceUrl
          *            the url of the loaded resource
-         * @param preload
-         *            true if the resource has only been preloaded, false if
-         *            it's fully loaded
          */
-        public ResourceLoadEvent(ResourceLoader loader, String resourceUrl,
-                boolean preload) {
+        public ResourceLoadEvent(ResourceLoader loader, String resourceUrl) {
             this.loader = loader;
             this.resourceUrl = resourceUrl;
-            this.preload = preload;
         }
 
         /**
-         * Gets the resource loader that has fired this event
+         * Gets the resource loader that has fired this event.
          *
          * @return the resource loader
          */
@@ -90,22 +80,10 @@ public class ResourceLoader {
             return resourceUrl;
         }
 
-        /**
-         * Returns true if the resource has been preloaded, false if it's fully
-         * loaded
-         *
-         * @see ResourceLoader#preloadResource(String, ResourceLoadListener)
-         *
-         * @return true if the resource has been preloaded, false if it's fully
-         *         loaded
-         */
-        public boolean isPreload() {
-            return preload;
-        }
     }
 
     /**
-     * Event listener that gets notified when a resource has been loaded
+     * Event listener that gets notified when a resource has been loaded.
      */
     public interface ResourceLoadListener {
         /**
@@ -143,10 +121,8 @@ public class ResourceLoader {
     private ApplicationConnection connection;
 
     private final Set<String> loadedResources = new HashSet<>();
-    private final Set<String> preloadedResources = new HashSet<>();
 
     private final Map<String, Collection<ResourceLoadListener>> loadListeners = new HashMap<>();
-    private final Map<String, Collection<ResourceLoadListener>> preloadListeners = new HashMap<>();
 
     private final Element head;
 
@@ -196,7 +172,6 @@ public class ResourceLoader {
      * doesn't cause the script to be loaded again, but the listener will still
      * be notified when appropriate.
      *
-     *
      * @param scriptUrl
      *            the url of the script to load
      * @param resourceLoadListener
@@ -204,29 +179,8 @@ public class ResourceLoader {
      */
     public void loadScript(final String scriptUrl,
             final ResourceLoadListener resourceLoadListener) {
-        loadScript(scriptUrl, resourceLoadListener,
-                !supportsInOrderScriptExecution());
-    }
-
-    /**
-     * Load a script and notify a listener when the script is loaded. Calling
-     * this method when the script is currently loading or already loaded
-     * doesn't cause the script to be loaded again, but the listener will still
-     * be notified when appropriate.
-     *
-     *
-     * @param scriptUrl
-     *            url of script to load
-     * @param resourceLoadListener
-     *            listener to notify when script is loaded
-     * @param async
-     *            What mode the script.async attribute should be set to
-     * @since 7.2.4
-     */
-    public void loadScript(final String scriptUrl,
-            final ResourceLoadListener resourceLoadListener, boolean async) {
         final String url = WidgetUtil.getAbsoluteUrl(scriptUrl);
-        ResourceLoadEvent event = new ResourceLoadEvent(this, url, false);
+        ResourceLoadEvent event = new ResourceLoadEvent(this, url);
         if (loadedResources.contains(url)) {
             if (resourceLoadListener != null) {
                 resourceLoadListener.onLoad(event);
@@ -234,31 +188,16 @@ public class ResourceLoader {
             return;
         }
 
-        if (preloadListeners.containsKey(url)) {
-            // Preload going on, continue when preloaded
-            preloadResource(url, new ResourceLoadListener() {
-                @Override
-                public void onLoad(ResourceLoadEvent event) {
-                    loadScript(url, resourceLoadListener);
-                }
-
-                @Override
-                public void onError(ResourceLoadEvent event) {
-                    // Preload failed -> signal error to own listener
-                    if (resourceLoadListener != null) {
-                        resourceLoadListener.onError(event);
-                    }
-                }
-            });
-            return;
-        }
-
         if (addListener(url, resourceLoadListener, loadListeners)) {
+            getLogger().info("Loading script from " + url);
             ScriptElement scriptTag = Document.get().createScriptElement();
             scriptTag.setSrc(url);
             scriptTag.setType("text/javascript");
 
-            scriptTag.setPropertyBoolean("async", async);
+            // async=false causes script injected scripts to be executed in the
+            // injection order. See e.g.
+            // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
+            scriptTag.setPropertyBoolean("async", false);
 
             addOnloadHandler(scriptTag, new ResourceLoadListener() {
                 @Override
@@ -275,105 +214,6 @@ public class ResourceLoader {
         }
     }
 
-    /**
-     * The current browser supports script.async='false' for maintaining
-     * execution order for dynamically-added scripts.
-     *
-     * @return Browser supports script.async='false'
-     * @since 7.2.4
-     */
-    public static boolean supportsInOrderScriptExecution() {
-        return BrowserInfo.get().isIE11() || BrowserInfo.get().isEdge();
-    }
-
-    /**
-     * Download a resource and notify a listener when the resource is loaded
-     * without attempting to interpret the resource. When a resource has been
-     * preloaded, it will be present in the browser's cache (provided the HTTP
-     * headers allow caching), making a subsequent load operation complete
-     * without having to wait for the resource to be downloaded again.
-     *
-     * Calling this method when the resource is currently loading, currently
-     * preloading, already preloaded or already loaded doesn't cause the
-     * resource to be preloaded again, but the listener will still be notified
-     * when appropriate.
-     *
-     * @param url
-     *            the url of the resource to preload
-     * @param resourceLoadListener
-     *            the listener that will get notified when the resource is
-     *            preloaded
-     */
-    public void preloadResource(String url,
-            ResourceLoadListener resourceLoadListener) {
-        url = WidgetUtil.getAbsoluteUrl(url);
-        ResourceLoadEvent event = new ResourceLoadEvent(this, url, true);
-        if (loadedResources.contains(url) || preloadedResources.contains(url)) {
-            // Already loaded or preloaded -> just fire listener
-            if (resourceLoadListener != null) {
-                resourceLoadListener.onLoad(event);
-            }
-            return;
-        }
-
-        if (addListener(url, resourceLoadListener, preloadListeners)
-                && !loadListeners.containsKey(url)) {
-            // Inject loader element if this is the first time this is preloaded
-            // AND the resources isn't already being loaded in the normal way
-
-            final Element element = getPreloadElement(url);
-            addOnloadHandler(element, new ResourceLoadListener() {
-                @Override
-                public void onLoad(ResourceLoadEvent event) {
-                    fireLoad(event);
-                    Document.get().getBody().removeChild(element);
-                }
-
-                @Override
-                public void onError(ResourceLoadEvent event) {
-                    fireError(event);
-                    Document.get().getBody().removeChild(element);
-                }
-            }, event);
-
-            Document.get().getBody().appendChild(element);
-        }
-    }
-
-    private static Element getPreloadElement(String url) {
-        /*-
-         * TODO
-         * In Chrome, FF:
-         * <object> does not fire event if resource is 404 -> eternal spinner.
-         * <img> always fires onerror -> no way to know if it loaded -> eternal spinner
-         * <script type="text/javascript> fires, but also executes -> not preloading
-         * <script type="text/cache"> does not fire events
-         *  XHR not tested - should work, probably causes other issues
-         -*/
-        if (BrowserInfo.get().isIE()) {
-            // If ie11+ for some reason gets a preload request
-            if (BrowserInfo.get().getBrowserMajorVersion() >= 11) {
-                throw new RuntimeException(
-                        "Browser doesn't support preloading with text/cache");
-            }
-            ScriptElement element = Document.get().createScriptElement();
-            element.setSrc(url);
-            element.setType("text/cache");
-            return element;
-        } else {
-            ObjectElement element = Document.get().createObjectElement();
-            element.setData(url);
-            if (BrowserInfo.get().isChrome()) {
-                element.setType("text/cache");
-            } else {
-                element.setType("text/plain");
-            }
-            element.setHeight("0px");
-            element.setWidth("0px");
-            return element;
-        }
-    }
-
     /**
      * Adds an onload listener to the given element, which should be a link or a
      * script tag. The listener is called whenever loading is complete or an
@@ -424,7 +264,7 @@ public class ResourceLoader {
     public void loadStylesheet(final String stylesheetUrl,
             final ResourceLoadListener resourceLoadListener) {
         final String url = WidgetUtil.getAbsoluteUrl(stylesheetUrl);
-        final ResourceLoadEvent event = new ResourceLoadEvent(this, url, false);
+        final ResourceLoadEvent event = new ResourceLoadEvent(this, url);
         if (loadedResources.contains(url)) {
             if (resourceLoadListener != null) {
                 resourceLoadListener.onLoad(event);
@@ -432,26 +272,8 @@ public class ResourceLoader {
             return;
         }
 
-        if (preloadListeners.containsKey(url)) {
-            // Preload going on, continue when preloaded
-            preloadResource(url, new ResourceLoadListener() {
-                @Override
-                public void onLoad(ResourceLoadEvent event) {
-                    loadStylesheet(url, resourceLoadListener);
-                }
-
-                @Override
-                public void onError(ResourceLoadEvent event) {
-                    // Preload failed -> signal error to own listener
-                    if (resourceLoadListener != null) {
-                        resourceLoadListener.onError(event);
-                    }
-                }
-            });
-            return;
-        }
-
         if (addListener(url, resourceLoadListener, loadListeners)) {
+            getLogger().info("Loading style sheet from " + url);
             LinkElement linkElement = Document.get().createLinkElement();
             linkElement.setRel("stylesheet");
             linkElement.setType("text/css");
@@ -533,12 +355,12 @@ public class ResourceLoader {
                     if (rules === undefined) {
                         rules = sheet.rules;
                     }
-
+    
                     if (rules === null) {
                         // Style sheet loaded, but can't access length because of XSS -> assume there's something there
                         return 1;
                     }
-
+    
                     // Return length so we can distinguish 0 (probably 404 error) from normal case.
                     return rules.length;
                 } catch (err) {
@@ -568,14 +390,8 @@ public class ResourceLoader {
     private void fireError(ResourceLoadEvent event) {
         String resource = event.getResourceUrl();
 
-        Collection<ResourceLoadListener> listeners;
-        if (event.isPreload()) {
-            // Also fire error for load listeners
-            fireError(new ResourceLoadEvent(this, resource, false));
-            listeners = preloadListeners.remove(resource);
-        } else {
-            listeners = loadListeners.remove(resource);
-        }
+        Collection<ResourceLoadListener> listeners = loadListeners
+                .remove(resource);
         if (listeners != null && !listeners.isEmpty()) {
             for (ResourceLoadListener listener : listeners) {
                 if (listener != null) {
@@ -587,19 +403,9 @@ public class ResourceLoader {
 
     private void fireLoad(ResourceLoadEvent event) {
         String resource = event.getResourceUrl();
-        Collection<ResourceLoadListener> listeners;
-        if (event.isPreload()) {
-            preloadedResources.add(resource);
-            listeners = preloadListeners.remove(resource);
-        } else {
-            if (preloadListeners.containsKey(resource)) {
-                // Also fire preload events for potential listeners
-                fireLoad(new ResourceLoadEvent(this, resource, true));
-            }
-            preloadedResources.remove(resource);
-            loadedResources.add(resource);
-            listeners = loadListeners.remove(resource);
-        }
+        Collection<ResourceLoadListener> listeners = loadListeners
+                .remove(resource);
+        loadedResources.add(resource);
         if (listeners != null && !listeners.isEmpty()) {
             for (ResourceLoadListener listener : listeners) {
                 if (listener != null) {
@@ -609,4 +415,7 @@ public class ResourceLoader {
         }
     }
 
+    private static Logger getLogger() {
+        return Logger.getLogger(ResourceLoader.class.getName());
+    }
 }