我如何同步从不同来源调用的回调(从回调中)?

How can i synchronize callbacks (from within the callback) called from different sources?

我的 ui-框架 (openui5) 在同步两个不同的回调时遇到问题。一个是来自渲染完成的 ui 事件的回调,另一个是来自数据访问(ajax 调用)的异步回调,由使用的模型 class 完成. ui-事件回调需要来自数据回调的数据。

为了简化这里的简化代码片段以演示问题。我想要,onRouteMatched-Code 应该在 onUpdateFinished 完成时执行代码。在此示例中,我使用我的 asyncInit-Method 创建了异步场景。这只是为了创建一个简单的测试场景。实际上,这个 onUpdateFinished 由我的数据模型 class 调用,onRouteMatched 由另一个框架 - class 事件调用。

let testClass = {

 myUser : "",

 // Method definition:
 asyncInit : function() {
   me = this;
   let timer1 = Math.round(Math.random()*10000);
   let timer2 = Math.round(Math.random()*10000);

   setTimeout(function(){ me.onUpdateFinished();} , timer1);
   setTimeout(function(){ me.onRouteMatched();} , timer2);
 },

 onUpdateFinished : function(oEvent) {
   console.warn("onUpdateFinished.....setting Data")
   this.myUser = 'doe';
 },

 onRouteMatched : function(oEvent) {
   // Event though this callback is 
   // called before onUpddate
   console.warn("onRouteMatched...., myData="+this.myUser);
 }

}
testClass.asyncInit();

在此示例中,onUpdateFinished 和 onRouteMatched 由 setTimeout 调用,超时值为 0-9 秒。 如果先调用 onUpdateFinished,则一切正常并且 onRouteMatched 中的用户是 "doe"。 如果在 onUpdateFinished 之前调用 onRouteMatched 则用户是 "undefined".

一个不太干净的解决方法是使用 "sync" 变量并在 onRouteMatched 中检查它(参见示例)。 我还想到了 promise、async 和 await 之类的东西。但正如我所见,在所有示例中,我必须能够控制在我的代码中启动回调。但在这种情况下,我对回调的调用者没有影响。

这里是我的例子 "workaround"

let testClass = {

 myUser : "",
 updOk  : false,

 // Method definition:
 asyncInit : function() {
   me = this;
   let timer1 = Math.round(Math.random()*10000);
   let timer2 = Math.round(Math.random()*10000);

   setTimeout(function(){ me.onUpdateFinished();} , timer1);
   setTimeout(function(){ me.onRouteMatched();} , timer2);
 },

 onUpdateFinished : function(oEvent) {
   console.warn("onUpdateFinished.....setting Data")
   this.myUser = 'doe';
   this.updOk = true;
 },

 onRouteMatched : function(oEvent) {
   // Event though this callback is 
   // called before onUpddate
   me = this;
   if (!this.updOk) {
     console.log("onRouteMatched called...");
     setTimeout(function(){ 
       console.warn("Update still not finished");
       me.onRouteMatched();
     },1000)
     return;
   }
   console.warn("onRouteMatched...., myData="+this.myUser);
 }

}
testClass.asyncInit();

围绕用户建立承诺:

let userArrived, user = new Promise(resolve => userArrived = resolve);

然后,在 onUpdateFinished 中解决承诺:

onUpdateFinished : function(oEvent) {
  userArrived("John Doe");
}

里面onRouteMatched消费承诺:

onRouteMatched : function(oEvent) {
  user.then(username => {
    console.log(`${username} is ready!`);
  });
}

或者使用 async / await 甚至可以写成:

async onRouteMatched(oEvent) {
  const username = await user;
  console.log(`${username} is ready!`);
},