GWT代码拆分同步请求

时间:2015-12-23 14:24:49

标签: javascript java ajax gwt

我在GWT中使用代码拆分来减少初始JavaScript的大小。 当我的应用程序初始化时,我想预取我的代码中的其他(更大)部分,如文档(www.gwtproject.org/doc/latest/DevGuideCodeSplitting.html)中所述。

private void doSth(final boolean prefetch) {
    GWT.runAsync(new RunAsyncCallback() {
        public void onFailure(Throwable caught) {
            Log.error("Loading the code failed!");
        }

        public void onSuccess() {
            if(prefetch)
                return; //do nothing. just a prefetch
            //here is the loaded code
        }
    });
}

但我无法承认性能的提升。在我分析浏览器日志时,我发现,加载JavaScript的请求未标记为XHR。 GWT是否同步加载分裂点的代码?

1 个答案:

答案 0 :(得分:4)

性能改进在初始下载的代码中,假设没有其他代码引用该代码。如果//here is the loaded code的工作还有其他功能,那么很少或根本没有代码可以分解为单独下载的JS文件。

可以通过多种方式禁用此功能,包括使用开发模式或设置编译器标志以跳过此过程。在这种情况下,是的,分裂点同步运行,因为等待是没有意义的。此外,在文件加载一次后,下次在同一页面加载中调用代码时不需要加载它。

如果您的服务器设置为正确缓存,那么在第一次访问之后,由于无需下载,因此节省的成本更低 - 您只需节省将该代码解析到浏览器的JS VM所需的时间。

但除此之外,我们还需要更多信息。

这是一个快速演示,演示了如何使用更多内容编写分割点,并让您使用浏览器注意分割点代码是如何单独引入的。

public class SampleEntryPoint implements EntryPoint {
  public void onModuleLoad() {
    Label label = new Label("Hello, World!");
    label.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event) {
        GWT.runAsync(new RunAsyncCallback() {
          public void onFailure(Throwable var1) {/*ignore*/}
          public void onSuccess() {
            Window.alert("Clicked, and loaded in split point!");
          }
        });
      }
    });
    RootPanel.get().add(label);
  }
}

代码和示例: https://viola.colinalworth.com/proj/755e224e7f48a047703d44eb6903d926/project/client/SampleEntryPoint.java

独立样本: https://viola.colinalworth.com:444/compiled/755e224e7f48a047703d44eb6903f76c/

当您加载此页面时,nocache文件会加载,初始下载也会加载(通过Chrome浏览器的“检查程序”网络标签): initial download after page load

然后,当您单击Label小部件时,onClick会触发runAsync并下载额外的分割点(加上"剩余的"片段): additional downloads after split point

将这两个新条目添加到“网络”标签后,您会看到显示警告消息。后续点击不会导致这种轻微的延迟,也不会强迫这个额外的JS再次下载。

另请注意,这些不会作为AJAX / XHR调用加载,而是作为要添加到页面的脚本标记加载。单击Initiator列中的详细信息(未显示)会导致此(格式化以便于阅读):

function fb(a) {
    var b, c, d;
    d = (bb(), window);
    b = d.document;
    c = b.createElement('script');
    (!!a.a || a.b) && cb(c, a.a, a.b);
    eb(c, a.c);
    (b.head || b.getElementsByTagName('head')[0]).appendChild(c);
    return c
}

通过混淆代码,我们发现创建了<script>标记,并将其附加到页面的<head>

深入挖掘,我们可以发现AsyncFragmentLoader.LoadingStrategy界面描述了如何获取此片段,com/google/gwt/core/AsyncFragmentLoader.gwt.xml默认将此线连接到XhrLoadingStrategy。但是,xsxsiframe链接器都会将其更改为CrossSiteLoadingStrategyScriptTagLoadingStrategy。至于GWT的最新版本(您没有指定,所以我假设您使用的是最新版本),xsiframe链接器是默认的。来自Core.gwt.xml:

<add-linker name="xsiframe" />

我们可以通过切换到旧链接器来定制它,或者只是替换策略。请注意,切换XHR策略将阻止跨域加载正常工作(例如SuperDevMode),因此请小心。

就像AsyncFragmentLoader.gwt.xml将接口连接到XhrLoadingStrategy并且CrossSiteIframeLinker.gwt.xml将其更改为ScriptTagLoadingStrategy一样,我们可以将其更改回来。我们创建了一个用LoadingStrategy替换XhrLoadingStrategy的规则,并在我们的GWT继承.gwt.xml文件中的语句后列出它:

<replace-with class="com.google.gwt.core.client.impl.XhrLoadingStrategy">
    <when-type-is class="com.google.gwt.core.client.impl.AsyncFragmentLoader.LoadingStrategy" />
</replace-with>

这是旧的默认值作为std链接器(com.google.gwt.core.linker.IFrameLinker)的一部分所依赖的内容,但不再鼓励这种情况,可能会在以后的版本中删除。