JavaScript Promise 回调在 Promise 本身之前执行

The JavaScript Promise callback is executed before the Promise itself

目前我正在做一个Oracle APEX页面,里面有放置文档参数的表单。我的目标是改进机制,根据数据库中的某些信息定义表单的哪些字段可供用户使用,哪些字段不可用。

我制作了 PL/SQL 过程并编写了 JavaScript 函数(以及 AJAX 过程)来帮助我解决这个任务,但是当我需要在定义可编辑的字段后执行一些JavaScript代码(例如,有时需要刷新一些与表单绑定的报表或从HTML页面中删除一些辅助元素).换句话说,我有函数enableFields(在参数页面加载时执行),它必须执行enableFieldsBase,然后回调函数callbackFunc 定义在输入参数中,但经过一些测试我发现后者执行 before 前者尽管使用 JavaScript承诺。

这里是 JavaScript 函数,它使用数据库中的信息使表单字段可用(或不可用):

function enableFieldsBase(){
    var page = 'P' + $v('pFlowStepId') + '_'; //define the page
    var docID = $v(page + 'DOC_ID'); //define the document

    //get the information which fields are available and which are not
    $.post('wwv_flow.show', 
      {'p_request'      : 'APPLICATION_PROCESS=DOC_ENABLE_FIELDS',
       'p_flow_id'      : $v('pFlowId'),
       'p_flow_step_id' : $v('pFlowStepId'),
       'p_instance'     : $v('pInstance'),
       'x01'            : docID},
    function(pData) {
      var res = eval('(' + pData+ ')');
      if (res.status == "OK") {
        //get the array of objects containing the shortened element names and the availability sign
        var props = res.data;
        //open or close the elements for edit
        for (var i = 0; i < props.length; i++){
          if (props[i].enabled == 1) apex.item(page + props[i].prop).enable();
          else apex.item(page + props[i].prop).disable();
        }
      } else {
         //…the code for catching the exceptions…
      }
    });
}

而这个就是JavaScript函数,它不仅执行了前面那个,还兼顾了回调函数:

function enableFields(callbackFunc){
  var page = 'P' + $v('pFlowStepId') + '_';
    
  //check if the variable callbackFunc is really a function
  if (callbackFunc != undefined && typeof(callbackFunc) != 'function'){
    //…the code for catching the exceptions…
  }
    
  if (callbackFunc != undefined){
    var promise1 = new Promise(function(resolve,reject){
      enableFieldsBase();
      return resolve(true);
    });
    $.when(promise1).done(function(){
      callbackFunc();
    });
  } else {
    enableFieldsBase();
  }
}

所以,我的问题如下:我做错了什么?是否可以将回调函数显式放入enableFieldsBase的代码中?

我使用 Oracle 11g 和 Oracle APEX 4.2.6.00.03。

问题是您同步调用了 resolve,没有等待 post 请求完成。所以承诺立即解决。

相反,您应该使用 $.post return 开箱即用的承诺:

function enableFieldsBase(){
    var page = 'P' + $v('pFlowStepId') + '_'; //define the page
    var docID = $v(page + 'DOC_ID'); //define the document

    //make sure to RETURN the result of the `$.post` call, and chain a `then` method call
    return $.post('wwv_flow.show', 
      {'p_request'      : 'APPLICATION_PROCESS=DOC_ENABLE_FIELDS',
       'p_flow_id'      : $v('pFlowId'),
       'p_flow_step_id' : $v('pFlowStepId'),
       'p_instance'     : $v('pInstance'),
       'x01'            : docID}).then(function(pData) { // Use the `then` method
      var res = eval('(' + pData+ ')');
      if (res.status == "OK") {
        //get the array of objects containing the shortened element names and the availability sign
        var props = res.data;
        //open or close the elements for edit
        for (var i = 0; i < props.length; i++){
          if (props[i].enabled == 1) apex.item(page + props[i].prop).enable();
          else apex.item(page + props[i].prop).disable();
        }
      } else {
         //…the code for catching the exceptions…
      }
    });
}

调用代码中:

if (callbackFunc != undefined){
    enableFieldsBase().then(callbackFunc);
} else {
    enableFieldsBase();
}

正如 jonrsharpe 在下面的评论中指出的那样,如果您向 then 传递一个不可调用的参数(如 undefined),就好像您根本没有传递回调。所以可以进一步简化为:

enableFieldsBase().then(callbackFunc);

最好将 callbackFunc 参数删除为 enableFields,而仅 return 承诺。 enableFields 的调用者应该自己决定是否要将 then 调用链接到它(或使用 await)。