Emscripten sandwiched by asynchronous Javascript Code












1















I'm trying to use Emscripten to write a Software to run in browser but also on other architectures (e.g. Android, PC-standalone app).



The Software structure is something like this:



main_program_loop() {
if (gui.button_clicked()) {
run_async(some_complex_action, gui.text_field.to_string())
}
if (some_complex_action_has_finished())
{
make_use_of(get_result_from_complex_action());
}
}

some_complex_action(string_argument)
{
some_object = read_local(string_argument);
interm_res = simple_computation(some_object);
other_object = expensive_computation(interm_res);
send_remote(some_object.member_var, other_object);
return other_object.member_var;
}


Let's call main_program_loop the GUI or frontend, some_complex_action the intermediate layer, and read_local, send_remode and expensive_computation the backend or lower layer.



Now the frontend and backend would be architecture specific (e.g. for Javascript read_local could use IndexDB, send_remote could use fetch),
but the intermediate layer should make up more then 50% of the code (that's why I do not want to write it two times in two different languages, and instead write it once in C and transpile it to Javascript, for Android I would use JNI).



Problems come in since in Javascript the functions on the lowest layer (fetch etc) run asyncronously (return a promise or require a callback).



One approach I tried was to use promises and send IDs through the intermediate layer



var promises = {};
var last_id = 0;
handle_click() {
var id = Module.ccall('some_complex_action', 'number', ['string'], [text_field.value]);
promises[id].then((result) => make_us_of(result));
}

recv_remote: function(str) {
promises[last_id] = fetch(get_url(str)).then((response) => response.arrayBuffer());
last_id += 1;
return last_id - 1;
}


It works for the simple case of



some_complex_action(char *str)
{
return recv_remote(str);
}


But for real cases it seem to be getting really complicated, maybe impossible. (I tried some approach where I'd given every function a state and every time a backend function finishes, the function is recalled and advances it's state or so, but the code started getting complicated like hell.) To compare, if I was to call some_complex_action from C or Java, I'd just call it in a thread separate from the GUI thread, and inside the thread everything would happen synchronously.



I wished I could just call some_complex_action from an async function and put await inside recv_remote but of cause I can put await only directly in the async function, not in some function called down the line. So that idea did not work out either.



Ideally if somehow I could stop execution of the intermediate Emscripten transpiled code until the backend function has completed, then return from the backend function with the result and continue executing the transpiled code.



Has anyone used Emterpreter and can imagine that it could help me get to my goal?



Any ideas what I could do?










share|improve this question





























    1















    I'm trying to use Emscripten to write a Software to run in browser but also on other architectures (e.g. Android, PC-standalone app).



    The Software structure is something like this:



    main_program_loop() {
    if (gui.button_clicked()) {
    run_async(some_complex_action, gui.text_field.to_string())
    }
    if (some_complex_action_has_finished())
    {
    make_use_of(get_result_from_complex_action());
    }
    }

    some_complex_action(string_argument)
    {
    some_object = read_local(string_argument);
    interm_res = simple_computation(some_object);
    other_object = expensive_computation(interm_res);
    send_remote(some_object.member_var, other_object);
    return other_object.member_var;
    }


    Let's call main_program_loop the GUI or frontend, some_complex_action the intermediate layer, and read_local, send_remode and expensive_computation the backend or lower layer.



    Now the frontend and backend would be architecture specific (e.g. for Javascript read_local could use IndexDB, send_remote could use fetch),
    but the intermediate layer should make up more then 50% of the code (that's why I do not want to write it two times in two different languages, and instead write it once in C and transpile it to Javascript, for Android I would use JNI).



    Problems come in since in Javascript the functions on the lowest layer (fetch etc) run asyncronously (return a promise or require a callback).



    One approach I tried was to use promises and send IDs through the intermediate layer



    var promises = {};
    var last_id = 0;
    handle_click() {
    var id = Module.ccall('some_complex_action', 'number', ['string'], [text_field.value]);
    promises[id].then((result) => make_us_of(result));
    }

    recv_remote: function(str) {
    promises[last_id] = fetch(get_url(str)).then((response) => response.arrayBuffer());
    last_id += 1;
    return last_id - 1;
    }


    It works for the simple case of



    some_complex_action(char *str)
    {
    return recv_remote(str);
    }


    But for real cases it seem to be getting really complicated, maybe impossible. (I tried some approach where I'd given every function a state and every time a backend function finishes, the function is recalled and advances it's state or so, but the code started getting complicated like hell.) To compare, if I was to call some_complex_action from C or Java, I'd just call it in a thread separate from the GUI thread, and inside the thread everything would happen synchronously.



    I wished I could just call some_complex_action from an async function and put await inside recv_remote but of cause I can put await only directly in the async function, not in some function called down the line. So that idea did not work out either.



    Ideally if somehow I could stop execution of the intermediate Emscripten transpiled code until the backend function has completed, then return from the backend function with the result and continue executing the transpiled code.



    Has anyone used Emterpreter and can imagine that it could help me get to my goal?



    Any ideas what I could do?










    share|improve this question



























      1












      1








      1








      I'm trying to use Emscripten to write a Software to run in browser but also on other architectures (e.g. Android, PC-standalone app).



      The Software structure is something like this:



      main_program_loop() {
      if (gui.button_clicked()) {
      run_async(some_complex_action, gui.text_field.to_string())
      }
      if (some_complex_action_has_finished())
      {
      make_use_of(get_result_from_complex_action());
      }
      }

      some_complex_action(string_argument)
      {
      some_object = read_local(string_argument);
      interm_res = simple_computation(some_object);
      other_object = expensive_computation(interm_res);
      send_remote(some_object.member_var, other_object);
      return other_object.member_var;
      }


      Let's call main_program_loop the GUI or frontend, some_complex_action the intermediate layer, and read_local, send_remode and expensive_computation the backend or lower layer.



      Now the frontend and backend would be architecture specific (e.g. for Javascript read_local could use IndexDB, send_remote could use fetch),
      but the intermediate layer should make up more then 50% of the code (that's why I do not want to write it two times in two different languages, and instead write it once in C and transpile it to Javascript, for Android I would use JNI).



      Problems come in since in Javascript the functions on the lowest layer (fetch etc) run asyncronously (return a promise or require a callback).



      One approach I tried was to use promises and send IDs through the intermediate layer



      var promises = {};
      var last_id = 0;
      handle_click() {
      var id = Module.ccall('some_complex_action', 'number', ['string'], [text_field.value]);
      promises[id].then((result) => make_us_of(result));
      }

      recv_remote: function(str) {
      promises[last_id] = fetch(get_url(str)).then((response) => response.arrayBuffer());
      last_id += 1;
      return last_id - 1;
      }


      It works for the simple case of



      some_complex_action(char *str)
      {
      return recv_remote(str);
      }


      But for real cases it seem to be getting really complicated, maybe impossible. (I tried some approach where I'd given every function a state and every time a backend function finishes, the function is recalled and advances it's state or so, but the code started getting complicated like hell.) To compare, if I was to call some_complex_action from C or Java, I'd just call it in a thread separate from the GUI thread, and inside the thread everything would happen synchronously.



      I wished I could just call some_complex_action from an async function and put await inside recv_remote but of cause I can put await only directly in the async function, not in some function called down the line. So that idea did not work out either.



      Ideally if somehow I could stop execution of the intermediate Emscripten transpiled code until the backend function has completed, then return from the backend function with the result and continue executing the transpiled code.



      Has anyone used Emterpreter and can imagine that it could help me get to my goal?



      Any ideas what I could do?










      share|improve this question
















      I'm trying to use Emscripten to write a Software to run in browser but also on other architectures (e.g. Android, PC-standalone app).



      The Software structure is something like this:



      main_program_loop() {
      if (gui.button_clicked()) {
      run_async(some_complex_action, gui.text_field.to_string())
      }
      if (some_complex_action_has_finished())
      {
      make_use_of(get_result_from_complex_action());
      }
      }

      some_complex_action(string_argument)
      {
      some_object = read_local(string_argument);
      interm_res = simple_computation(some_object);
      other_object = expensive_computation(interm_res);
      send_remote(some_object.member_var, other_object);
      return other_object.member_var;
      }


      Let's call main_program_loop the GUI or frontend, some_complex_action the intermediate layer, and read_local, send_remode and expensive_computation the backend or lower layer.



      Now the frontend and backend would be architecture specific (e.g. for Javascript read_local could use IndexDB, send_remote could use fetch),
      but the intermediate layer should make up more then 50% of the code (that's why I do not want to write it two times in two different languages, and instead write it once in C and transpile it to Javascript, for Android I would use JNI).



      Problems come in since in Javascript the functions on the lowest layer (fetch etc) run asyncronously (return a promise or require a callback).



      One approach I tried was to use promises and send IDs through the intermediate layer



      var promises = {};
      var last_id = 0;
      handle_click() {
      var id = Module.ccall('some_complex_action', 'number', ['string'], [text_field.value]);
      promises[id].then((result) => make_us_of(result));
      }

      recv_remote: function(str) {
      promises[last_id] = fetch(get_url(str)).then((response) => response.arrayBuffer());
      last_id += 1;
      return last_id - 1;
      }


      It works for the simple case of



      some_complex_action(char *str)
      {
      return recv_remote(str);
      }


      But for real cases it seem to be getting really complicated, maybe impossible. (I tried some approach where I'd given every function a state and every time a backend function finishes, the function is recalled and advances it's state or so, but the code started getting complicated like hell.) To compare, if I was to call some_complex_action from C or Java, I'd just call it in a thread separate from the GUI thread, and inside the thread everything would happen synchronously.



      I wished I could just call some_complex_action from an async function and put await inside recv_remote but of cause I can put await only directly in the async function, not in some function called down the line. So that idea did not work out either.



      Ideally if somehow I could stop execution of the intermediate Emscripten transpiled code until the backend function has completed, then return from the backend function with the result and continue executing the transpiled code.



      Has anyone used Emterpreter and can imagine that it could help me get to my goal?



      Any ideas what I could do?







      javascript asynchronous emscripten






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 17 '18 at 19:47







      matec

















      asked Nov 17 '18 at 19:29









      matecmatec

      4591516




      4591516
























          0






          active

          oldest

          votes











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53354781%2femscripten-sandwiched-by-asynchronous-javascript-code%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53354781%2femscripten-sandwiched-by-asynchronous-javascript-code%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          這個網誌中的熱門文章

          Xamarin.form Move up view when keyboard appear

          Post-Redirect-Get with Spring WebFlux and Thymeleaf

          Anylogic : not able to use stopDelay()