开发者问题收集

异步 Javascript 函数在承诺中未正确调用

2016-10-11
94

我有以下代码:

//this 'hitches' the scope to the appropriate callback method
var hitchWidgetToPopulateHierarchyDefinitionFields = DojoBaseLang.hitch(this, populateHierarchyDefinitionFieldsFromSelectedHierarchyTable);
hitchWidgetToPopulateHierarchyDefinitionFields();

function selectValuesByFieldFromHierarchyTable(currentlySelectedColumn) {
     //query database and return an array of strings
 }

function addHierarchyLevelSelectionToDOM (hierarchyLevelsArray) {
   var temporaryDataStore= [];
   for (var i=0; i<hierarchyLevelsArray.length;i++){
       //DO STUFF
   }
}
function populateHierarchyDefinitionFieldsFromSelectedHierarchyTable(){
    var selectedHierarchyDefinitionColumn = "COLUMN_NAME"
    var p1 = new Promise(function( resolve, reject) {
        setTimeout(function() {
            resolve(selectValuesByFieldFromHierarchyTable(selectedHierarchyDefinitionColumn))
        },2000);
    });
    p1.then(
        function resolve(value) {
            console.log(value);
            addHierarchyLevelSelectionToDOM(value);
        }
    ).catch(
        function reject(error) {
            console.error(error);
        }
    );
}

这会导致控制台输出记录该值,但 addHierarchyLevelSelectionToDOM 中的值仍未定义:

TypeError: Cannot read property 'length' of undefined
Object {Relevant data }

请注意,该对象确实已记录,并且错误已在 catch 中捕获。

我的意图只是从 selectValuesByFieldFromHierarchyTable 返回的值调用 addHierarchyLevelSelectionToDOM 。问题是,当调用 addHierarchyLevelSelectionToDOM(value) 时,该值未定义,但 console.log(value) 调用会打印正确的返回值。然后我尝试了多个承诺,但都得到了相同的结果:

var p1 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve(selectValuesByFieldFromHierarchyTable(selectedHierarchyDefinitionColumn))
  }, 2000);
});
var p2 = p1.then(function(value) {
  console.log(value);
  return new Promise(addHierarchyLevelSelectionToDOM(value));
});
p2.then(function(value) {
  console.log(value);
});

当然,在这种情况下,由于解析 addHierarchyLevelSelectionToDOM(value) 失败,第二个 console.log(value) 未被调用。如果可能的话,我想用纯 Javascript 实现这个目标。

非常感谢任何帮助!

3个回答

至少对于您的第一个问题(已删除),您很可能在 Promise 构造函数中遇到了错误,更准确地说是在 selectValuesByFieldFromHierarchyTable

只需执行:

var p1 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve("bla");
  }, 2000);
});
p1.then(function(value) {
  console.log(value);
});

然后它突然就起作用了。因此,这就是为什么在大多数情况下您也应该有一个拒绝函数的原因,因为拒绝()不仅在您手动拒绝时被调用,而且在抛出错误时也会被调用 - 无论出于何种原因:

p1.then(
  function resolve(value) {
      console.log(value);
  },
  function reject(error) {
      console.error(error);
  }
);

但是等等!现在,如果您在“resolve”中遇到错误,它也会默默失败。因此,最好使用此模式:

p1.then(
  function resolve(value) {
      console.log(value);
  }
).catch(
  function reject(error) {
      console.error(error);
  }
);

再试一次,情况应该会更清晰。

(请注意,函数命名不是强制性的,但有助于调试)

编辑:关于“纯 Javascript”。那么,你的意思是什么?那是纯 Javascript,而 Promises 也是标准。大多数现代浏览器都可以原生地做到这一点,对于其余的浏览器,只需使用应该可以完美运行的 polyfill,因为 Promises 可以 100%“模拟”。

frontend_dev
2016-10-11

尝试一下:

var p1 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve(selectValuesByFieldFromHierarchyTable(selectedHierarchyDefinitionColumn.innerHTML))
  }, 2000);
});
p1.then(addHierarchyLevelSelectionToDOM);
Gonzalo Pincheira Arancibia
2016-10-11

代码的问题在于 selectValuesByFieldFromHierarchyTable

代码中调用了一个异步函数 queryFeatures ,其类型为 Deferred

解决方案是返回延迟(异步)类型,然后返回所需的数据数组 uniqueHierarchyLevels

function selectValuesByFieldFromHierarchyTable(currentlySelectedColumn) {
    //query database and return an array of strings
    //now returning the deferred type returned by queryFeatures as well as the array
     return hierarchyTableFeatureLayer.queryFeatures(hierarchyTableQuery, function(featureSet){

         for (var i = 0; i<featureSet.features.length; i++){
             uniqueHierarchyLevels.push(featureSet.features[i])
         }
     }).then(function afterQuery(){
            return uniqueHierarchyLevels;
        });
}

function populateHierarchyDefinitionFieldsFromSelectedHierarchyTable(){
    var selectedHierarchyDefinitionColumn = "COLUMN_NAME";
    deferred.resolve(selectUniqueValuesByFieldFromHierarchyTable(selectedHierarchyDefinitionColumn));
    deferred.then(function queryFeaturesAsyncCall(featureSetCallback) {
        featureSetCallback.then(
            function (hierarchyLevelsArray) {
                addHierarchyLevelSelectionToDOM(hierarchyLevelsArray);
            },
            function (err) {
            // Do something when the process errors out
                 console.log(err);
            })
       });
}
Rice
2016-10-11