Uploaded image for project: 'Tapestry 5'
  1. Tapestry 5
  2. TAP5-1734

Race condition loading JavaScript libraries with ProgressiveDisplay

    XMLWordPrintableJSON

Details

    Description

      Using the ProgressiveDisplay component twice on a page can cause a JS (Tapestry.Initializer) call to fail. Specifically both ProgressiveDisplays have to contain a component which loads a javascript. If both ProgressiveDisplays try to show the component at the very same time the first gets through (and now my guess: and is processing the JS, in the meantime the second arrives and recognizes the JS is already loaded so it just goes ahead and calls it, as it's not fully processed yet the call fails, when the first one is done processing it executes the JS and everything works fine, of course the second one already failed and doesn't work).
      I did a small sample project to confirm my assumptions:

      The page:
      @MixinClasses(DummyMixin.class)
      @Component(parameters =

      {"DummyMixin.value=FirstComponent"}

      )
      private DummyComponent comp;

      @MixinClasses(DummyMixin.class)
      @Component(parameters =

      {"sleepTime=2950", "DummyMixin.value=SecondComponent"}

      )
      private DummyComponent comp2;

      with the tml:
      <t:ProgressiveDisplay update="show">
      <div t:id="comp" />
      </t:ProgressiveDisplay>

      <t:ProgressiveDisplay update="show">
      <div t:id="comp2" />
      </t:ProgressiveDisplay>

      My component:
      @Parameter(value = "3000")
      private int sleepTime;

      @Component(parameters =

      {"value=testDTO.description"}

      )
      private TextField textField;

      @Property
      private TestDTO testDTO;

      public void beginRender()
      {
      try

      { Thread.sleep(sleepTime); }

      catch (InterruptedException e)

      { // nothing }

      testDTO = new TestDTO(1L, "some description");
      }

      And it's tml:
      <t:container xmlns="tapestry:parameter"
      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">

      <t:form>
      <div t:id="textField"/>
      </t:form>
      </t:container>

      And last but not least the mixin:
      public class DummyMixin
      {
      @Parameter(defaultPrefix = BindingConstants.LITERAL)
      private String value;

      @Inject
      @Path("dummy-mixin.js")
      @Property(write = false)
      private Asset mixinScript;

      @Environmental
      private JavaScriptSupport jsSupport;

      @BeginRender
      void beginRender(final MarkupWriter writer)

      { jsSupport.importJavaScriptLibrary(mixinScript); }

      @CleanupRender
      void initializeJavaScript(final MarkupWriter writer)

      { jsSupport.addInitializerCall(InitializationPriority.NORMAL, "mixinScript", new JSONObject("value", value)); }

      }

      *And it's JS file:*
      Tapestry.Initializer.mixinScript = function(spec) {
      console.log("worked - " + spec.value);
      };

      I tried it many many times with comp set to 3000 by default and comp2 set to 100, the error never occured. With the setting above (2950) the error occured about 3 out of 5 times and with both set to 3000 the error occured each time (same in every browser i tried: Opera, Firefox, IE 8, Chrome).
      During copying my code into JIRA i figured i could try InitializationPriority.IMMEDIATE but regrettably this also didn't do the trick, even it seems the error appears less likely when close together but still each time when the same timeout is set

      Attachments

        Activity

          People

            hlship Howard Lewis Ship
            matt11 Matthias Melitzer
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: