Makes GWT.runAsync to always run async.
Fixes issue 5560
Change-Id: Ia55b41c6978a7d2824ceeb3289dc48fe05bf117b
Review-Link: https://gwt-review.googlesource.com/#/c/2770/
diff --git a/user/src/com/google/gwt/core/client/GWT.java b/user/src/com/google/gwt/core/client/GWT.java
index f9b68b2..3d3440d 100644
--- a/user/src/com/google/gwt/core/client/GWT.java
+++ b/user/src/com/google/gwt/core/client/GWT.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.core.client;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.core.client.impl.Impl;
/**
@@ -258,14 +259,18 @@
*/
@SuppressWarnings("unused") // parameter will be used following replacement
public static void runAsync(Class<?> name, RunAsyncCallback callback) {
- callback.onSuccess();
+ runAsync(callback);
}
/**
* Run the specified callback once the necessary code for it has been loaded.
*/
- public static void runAsync(RunAsyncCallback callback) {
- callback.onSuccess();
+ public static void runAsync(final RunAsyncCallback callback) {
+ Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+ @Override public void execute() {
+ callback.onSuccess();
+ }
+ });
}
/**
diff --git a/user/src/com/google/gwt/core/client/impl/AsyncFragmentLoader.java b/user/src/com/google/gwt/core/client/impl/AsyncFragmentLoader.java
index 528a734..77ab67f 100644
--- a/user/src/com/google/gwt/core/client/impl/AsyncFragmentLoader.java
+++ b/user/src/com/google/gwt/core/client/impl/AsyncFragmentLoader.java
@@ -18,6 +18,8 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.RunAsyncCallback;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
/**
* <p>
@@ -587,7 +589,7 @@
private void runAsyncImpl(final int fragment, RunAsyncCallback callback) {
if (isLoaded[fragment]) {
assert allCallbacks[fragment] == null;
- callback.onSuccess();
+ executeOnSuccessAsynchronously(callback);
return;
}
@@ -615,6 +617,28 @@
}
}
+ /**
+ * Executes onSuccess asynchronously.
+ */
+ private void executeOnSuccessAsynchronously(final RunAsyncCallback callback) {
+ Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+ @Override public void execute() {
+ executeOnSuccess(callback);
+ }
+ });
+ }
+
+ private void executeOnSuccess(RunAsyncCallback callback) {
+ /*
+ * Calls on {@link RunAsyncCallback#onSuccess} from {@link AsyncFragmentLoader} is special
+ * treated (See RescueVisitor in ControlFlowAnalyzer) so that code splitter will not follow them
+ * on fragment analysis. That is, if don't call onSuccess from here and instead call it directly
+ * from the scheduled command, then it will make the code splitter put the split point code in
+ * the initial fragment.
+ */
+ callback.onSuccess();
+ }
+
private void startLoadingFragment(int fragment) {
assert (fragmentLoading < 0);
fragmentLoading = fragment;
diff --git a/user/test/com/google/gwt/dev/jjs/test/RunAsyncFailureTest.java b/user/test/com/google/gwt/dev/jjs/test/RunAsyncFailureTest.java
index 65d6fae..8b771cf 100644
--- a/user/test/com/google/gwt/dev/jjs/test/RunAsyncFailureTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/RunAsyncFailureTest.java
@@ -17,6 +17,8 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.RunAsyncCallback;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.RepeatingCommand;
import com.google.gwt.core.client.impl.LoadingStrategyBase;
import com.google.gwt.junit.DoNotRunWith;
import com.google.gwt.junit.Platform;
@@ -82,6 +84,8 @@
private static final int RUNASYNC_TIMEOUT = 30000;
+ private static int staticWrittenByAsync;
+
@Override
public String getModuleName() {
return "com.google.gwt.dev.jjs.RunAsyncFailure";
@@ -165,6 +169,19 @@
}
});
}
+
+ private void runAsync5() {
+ GWT.runAsync(new RunAsyncCallback() {
+ public void onFailure(Throwable caught) {
+ staticWrittenByAsync++;
+ }
+ public void onSuccess() {
+ // Use the string "INSTALL_FAILURE_TEST" so we can identify this
+ // fragment on the server. In the fail message is good enough.
+ fail("INSTALL_FAILURE_TEST_2 - Code should have failed to install!");
+ }
+ });
+ }
/**
* Test the basic functionality of retrying runAsync until is succeeds.
@@ -201,4 +218,33 @@
LoadingStrategyBase.MAX_AUTO_RETRY_COUNT = 3;
runAsync4();
}
+
+ public void testDownloadSuccessButInstallFailureStillRunsAsync() {
+ delayTestFinish(RUNASYNC_TIMEOUT);
+ LoadingStrategyBase.MAX_AUTO_RETRY_COUNT = 3;
+ staticWrittenByAsync = 0;
+
+ assertRunAsyncIsAsync();
+
+ // Give it little bit more time to loaded and try runAsync again
+ Scheduler.get().scheduleFixedPeriod(new RepeatingCommand() {
+ @Override public boolean execute() {
+ if (staticWrittenByAsync == 0) {
+ return true;
+ }
+
+ // Code is loaded, let's assert it still runs async
+ assertRunAsyncIsAsync();
+
+ finishTest();
+ return false;
+ }
+ }, 100);
+ }
+
+ private void assertRunAsyncIsAsync() {
+ final int lastValue = staticWrittenByAsync;
+ runAsync5();
+ assertEquals(lastValue, staticWrittenByAsync);
+ }
}
diff --git a/user/test/com/google/gwt/dev/jjs/test/RunAsyncTest.java b/user/test/com/google/gwt/dev/jjs/test/RunAsyncTest.java
index e9e7c94..38a8e6c 100644
--- a/user/test/com/google/gwt/dev/jjs/test/RunAsyncTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/RunAsyncTest.java
@@ -18,6 +18,8 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
import com.google.gwt.core.client.RunAsyncCallback;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.RepeatingCommand;
import com.google.gwt.junit.client.GWTTestCase;
/**
@@ -30,6 +32,8 @@
private static String staticWrittenInBaseButReadLater;
+ private static int staticWrittenByAsync;
+
@Override
public String getModuleName() {
return "com.google.gwt.dev.jjs.CompilerSuite";
@@ -73,6 +77,44 @@
}
/**
+ * Test runAsync always runs async.
+ */
+ public void testAsyncIsAlwaysAsync() {
+ delayTestFinish(RUNASYNC_TIMEOUT);
+ staticWrittenByAsync = 0;
+
+ assertRunAsyncIsAsync();
+
+ // Give it little bit more time to loaded and try runAsync again
+ Scheduler.get().scheduleFixedPeriod(new RepeatingCommand() {
+ @Override public boolean execute() {
+ if (staticWrittenByAsync == 0) {
+ return true;
+ }
+
+ // Code is loaded, let's assert it still runs async
+ assertRunAsyncIsAsync();
+
+ finishTest();
+ return false;
+ }
+ }, 100);
+ }
+
+ private void assertRunAsyncIsAsync() {
+ final int lastValue = staticWrittenByAsync;
+ GWT.runAsync(RunAsyncTest.class, new RunAsyncCallback() {
+ public void onFailure(Throwable caught) {
+ throw new RuntimeException(caught);
+ }
+ public void onSuccess() {
+ staticWrittenByAsync++;
+ }
+ });
+ assertEquals(lastValue, staticWrittenByAsync);
+ }
+
+ /**
* Test that callbacks are called in the order they are posted.
*/
public void testOrder() {
@@ -130,17 +172,13 @@
});
delayTestFinish(RUNASYNC_TIMEOUT);
- try {
- GWT.runAsync(new RunAsyncCallback() {
- public void onFailure(Throwable caught) {
- }
+ GWT.runAsync(new RunAsyncCallback() {
+ public void onFailure(Throwable caught) {
+ }
- public void onSuccess() {
- throw toThrow;
- }
- });
- } catch (Throwable e) {
- GWT.maybeReportUncaughtException(e);
- }
+ public void onSuccess() {
+ throw toThrow;
+ }
+ });
}
}