Do javascript promises work well with lang.hitch?

1702
7
Jump to solution
08-11-2020 07:19 AM
MichaelLev
Occasional Contributor III

I am developing custom widget for esri Web AppBuilder 2.16 (I have not yet upgraded to 2.17).

 

Seems as if lang.hitch spoils working with promises. What to do? Is there a solution? some code examples?

Help will be greatly appreciated,

Michael

1 Solution

Accepted Solutions
CarlosNantes
New Contributor III

Michael, if you can't get it working with lang.hitch, there is another way you can track scoping inside a class. Here is an example  :

define([
 //...
], function (
 //...
) {
    var that;
    return declare(null, {
       someData: '',
       postCreate: function () {
         that = this;
         that.fetchSomeData().then(that.showData)
                             .otherwise(that.showError);

         // instead of:
         // this.fetchSomeData().then(lang.hitch(this, this.showData))
         ///                    .otherwise(lang.hitch(this, this.showError));

     },
     fetchSomeData: function(){
         var deferred = new Deferred();
         someAsyncQuery().then(function(response){
             that.someData = response;
             deferred.resolve(response);
         }).otherwise(function(error){
             deferred.reject(error);
         }); 
         return deferred.promise;
     },
     showData: function(response){
          alert(response);
     },
     showError:function(error){
          alert(error);
     }
 });
});‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I think lang.hitch does the job, but it makes the code really hard to read. 

View solution in original post

7 Replies
KenBuja
MVP Esteemed Contributor

Can you provide some examples where it isn't working?

MichaelLev
Occasional Contributor III

Dear Ken,

Only tomorrow I will be by my PC,

so I’ll try to explain:

I have custom widget and 2 classes (each in a file).

in the widget I want to do chain calls (with then) to several funcs from one class.

A func in the 2nd class calls function from 3rd class which in turn calls another async func in same 3rd class which returns promise.

Funcs in 2nd class could chain other funcs in the 2nd classs, using then.

And in all of this, I have to use Lang.hitch in order to keep tracking “this”.

I get errors complaining that the promise result is not defined, specially in “catch”.

It seems also that if I call the “chained” function within same 2nd class with lang.hitch, then I get error that “this.<funcname> is not known.

Tomorrow I’ll be able to send code.

(what I am trying to do, is to adapt the code exampleFME Server Playground to be a custom widget, so that the user will need only to choose the input file, but all other operations like getting info from workspace and uploading the input file and doing transformation, all will be done automatically one after the other by promises, where I don’t need all the html don element stuff.

Thanks for your willingness to help,

Michael

CarlosNantes
New Contributor III

Michael, if you can't get it working with lang.hitch, there is another way you can track scoping inside a class. Here is an example  :

define([
 //...
], function (
 //...
) {
    var that;
    return declare(null, {
       someData: '',
       postCreate: function () {
         that = this;
         that.fetchSomeData().then(that.showData)
                             .otherwise(that.showError);

         // instead of:
         // this.fetchSomeData().then(lang.hitch(this, this.showData))
         ///                    .otherwise(lang.hitch(this, this.showError));

     },
     fetchSomeData: function(){
         var deferred = new Deferred();
         someAsyncQuery().then(function(response){
             that.someData = response;
             deferred.resolve(response);
         }).otherwise(function(error){
             deferred.reject(error);
         }); 
         return deferred.promise;
     },
     showData: function(response){
          alert(response);
     },
     showError:function(error){
          alert(error);
     }
 });
});‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I think lang.hitch does the job, but it makes the code really hard to read. 

MichaelLev
Occasional Contributor III

Dear Carlos,

Thank you very much for the example code.

I came to a conclusion that  lang.hitch can't return regular javascript promise. 

So currently I'm using regular javascript promises, and I bypass the lang.hitch by using "that = this".

I'll update when I succeed (or have more problems...).

May I ask some questions, please?

  1. Am I right that lang.hitch can't return regular javascript promise? or am I missing something?
  2. I had problems with regular javascript promises, and expected help concerning them, but your code example uses "Deferred". Is there a serious reason to prefer "Deferred" upon regular javascript promises? Is "Deferred" more capable than regular javascript promises, or does it fit better into widgets?

Michael

0 Kudos
CarlosNantes
New Contributor III

Hi Michael.

1. Yes, regular javascript promises will work with lang.hitch. Here is a sample code:

define([
    'dojo/_base/declare',
    'dojo/_base/lang',
    'jimu/BaseWidget'
], function (
    declare,
    lang,
    BaseWidget
) {
    return declare([BaseWidget], {
       onOpen: function(){
          var shouldFail = false;
          this.fetchMessage(shouldFail).then(lang.hitch(this, this.processMessage))
                                       .then(lang.hitch(this, this.showMessage))
                                      .catch(lang.hitch(this, this.showMessage));
       },
       fetchMessage: function (shouldFail) {
          var milisseconds = 2000;
          return new Promise((resolve, reject) => {
             setTimeout(function () {
                if (shouldFail) {
                   reject('Error message');
                } else {
                   resolve('Success message');
                }
             }, milisseconds);
          });
       },
       processMessage: function (message) {
          var milisseconds = 2000;
          return new Promise((resolve, reject) => {
             setTimeout(function () {
                var processedData = "Processed " + message;
                resolve(processedData);
             }, milisseconds);
          });
      },
      showMessage:function(message){
         alert(message);
      }
   });
});‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

2. dojo/Deferred is a dojo module that implements Promises. I've noticed there is some diference between Deferred and regular javascript Promises, but the intent is the same for both of them. It seems better to use dojo/Deferred, because you can guarantee that this module will work in many browsers that dojo supports. Regular javascript Promises won't work in some browser versions, Internet Explorer 11 for example (check more here: https://caniuse.com/#search=Promise). Also, many, if not all, jimu modules implemented by ESRI use dojo/Deferred. By choosing it, you will prevent using 2 different modules that do the same thing, this reduces the amount of complexity to maintain your code and to understand ESRI code. Here is the documentation for the interface of dojo/promise: https://dojotoolkit.org/reference-guide/1.10/dojo/promise/Promise.html#dojo-promise-promise.

MichaelLev
Occasional Contributor III

Dear Carlos,

I appreciate you very much for your explanations and code examples!

I’ll learn from them.

Meantime, today I have implemented by javascript promises, using class-scope “that” as you suggested,

and avoiding lang.hitch, and the promises work perfect!

  • Only, part of the functions called by “that.funcname” lose the “this” inside of them, so I use the class-scope “that” inside them, and I don’t yet know the reason of that different behavior. Can you enlighten my eyes?

Now that I read your reply,

I have to:

  1. Check your “Lang.hitch” example, and if it works, I’ll have to set a version of my code with “Lang.hitch” and debug. Maybe because my func calls are between 2 different classes, the “Lang.hitch” has not returned promise? I’ll check.
  2. Check version of my code with “Deferred” to see I know to use it. I indeed saw that esri code uses “Deferred” much much more than regular javascript promises, so in order to better understand esri code, it makes sense to use “Deferred”.
  3. Indeed my application is recommended to use mainly on Chrome, so the fact that “Deferred” runs on more browsers is not critical, but of course it has to be taken in account, since in case another browser is needed, avoidIng using 2 versions side by side is important, as you pointed out.
  4. So, after creating version of my code using “Deferred”, I’ll have to decide which to use. I assume that javascript promises code is simpler, but I’ll compare after I have also “Deferred” version.
  5. Thank you very much for introducing me to “Deferred” and to the differences between it to javascript promises, for the clear code examples of “Deferred” and of “Lang.hitch” with javascript promises.

You helped me very much in learning that area, and the idea of class-wide “that” helped me very much.

With appreciation,

Michael

MichaelLev
Occasional Contributor III

Found that lang.hitch can't return a Promise.

Michael

0 Kudos