我有一个递归函数设置来重新创建/加载propertyTemplate数组。
第一个函数给出一个这样的对象:
{
staffedLocation: ['schedulingGroup',{property: 'staff',subProperties: ['description']}],
staff: true,
assignedShifts: true,
editedShifts: true,
deletedShifts: true,
unassignedShifts: true,
rangeStart: true,
rangeEnd: true
}
我需要将这个对象重新创建为一个对象数组,以便正确填充我的UI:
[
{checked: null, name: "staffedLocation", properties: [
{checked: null, name: "oid", properties: null, toggle: null, type: "integer"},
{checked: null, name: "_class", properties: null, toggle: null, type: "string"},
{checked: true, name: "schedulingGroups", properties: null, toggle: null, type: "list"},
{checked: null, name: "staff", properties: [
{checked: null, name: "oid", properties: null, toggle: null, type: "integer"},
{checked: null, name: "_class", properties: null, toggle: null, type: "string"},
{checked: true, name: "description", properties: null, toggle: null, type: "string"},
{checked: null, name: "limits", properties: null, toggle: null, type: "list"},
{checked: null, name: "weeklyMaxHours", properties: null, toggle: null, type: "integer"}
], toggle: true, type: "list"},
], toggle: true, type: "staffedLocation"},
{checked: null,
name: "staff", properties: [
{checked: null, name: "oid", properties: null, toggle: null, type: "integer"},
{checked: null, name: "_class", properties: null, toggle: null, type: "string"},
{checked: null, name: "description", properties: null, toggle: null, type: "string"},
{checked: null, name: "limits", properties: null, toggle: null, type: "list"},
{checked: null, name: "weeklyMaxHours", properties: null, toggle: null, type: "integer"}
], toggle: true, type: "staff"},
{checked: null, name: "assignedShifts", properties: null, toggle: null, type: "shiftForEmail"},
{checked: null, name: "editedShifts", properties: null, toggle: null, type: "shiftForEmail"},
{checked: null, name: "deletedShifts", properties: null, toggle: null, type: "shiftForEmail"},
{checked: null, name: "unassignedShifts", properties: null, toggle: null, type: "shiftForEmail"},
{checked: null, name: "rangeStart", properties: null, toggle: null, type: "timestamp"},
{checked: null, name: "rangeEnd", properties: null, toggle: null, type: "timestamp"}
]
目前,当我调用convert函数时,它会遍历并开始创建我的对象数组。但是,当它命中convertRecurse时,会创建一个promise以收集其中一个项的属性。
最初我认为在收集所有属性之后嵌套promise中的所有内容都会正常运行该函数。但是,当我第一次转到页面并加载模板时,属性不会出现。如果我再次重新打开模板,它会起作用。
我认为链接承诺会导致第二个承诺等待继续前进。但是,我对他们的工作原理并不了解。
function convert(template){
$scope.propertyTemplate = [];
for(var k in template){
var obj = {};
obj.checked = null;
obj.name = k;
if(template[k] !== true){
convertRecurse(template[k], obj, k);
} else {
obj.properties = null;
obj.toggle = null;
}
$scope.propertyTemplate.push(obj);
}
}
function convertRecurse(array, obj, parent){
var propArr = [];
var namespace = new namespaceFactory(parent);
namespace.init();
namespace.fetchProperties().then(function(props){
props.forEach(function(prop){
var fetchObj = {};
fetchObj.name = prop.property;
fetchObj.type = prop.type;
fetchObj.checked = null;
fetchObj.properties = null;
fetchObj.toggle = null;
propArr.push(fetchObj);
});
return propArr;
}).then(function(){
var objArr = [];
for(var j = 0; j < array.length; j++){
if(typeof array[j] === 'object'){
objArr.push(array[j]);
array.splice(j, 1);
j--;
}
for(var i = 0;i < propArr.length; i++){
if(array[j] === propArr[i].name){
propArr[i].checked = true;
}
}
}
for(var k = 0; k < objArr.length; k++){
var propObj = {};
propObj.checked = null;
propObj.name = objArr[k].property;
if(objArr[k].subProperties){
convertRecurse(objArr[k].subProperties, propObj, objArr[k].property)
for(var x = 0; x < propArr.length; x++){
if(propArr[x].name === propObj.name){
propArr.push(propObj);
propArr.splice(x, 1);
}
}
} else {
propObj.properties = null;
propObj.toggle = null;
}
}
obj.properties = propArr;
obj.toggle = true;
}).catch(console.log.bind(console));
}
我的问题是,当我第一次调用此函数时,它不会加载。
但是,如果我再次打电话,一切似乎都能完美运作。
答案 0 :(得分:1)
您遇到的问题涉及异步流程。当前编写的代码将convertRecurse()
视为同步,而实际上是异步的。
代码很难在某些地方使用,但棘手的部分是同步转换,我并未尝试理解。
修复非常广泛,部分原因是异步操作发生在循环中。更具体地说,您需要:
正如您将在下面看到的那样,异步流程的一个主要方面是全面地获得适当的回报。
这是采用顺序方法:
function convert(template) {
$scope.propertyTemplate = [];
// Make array of template's enumerable keys
// See https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
var keys = Object.keys(template);
// Build a .then() chain from `keys`.
return keys.reduce(function(promise, k) {
return promise.then(function() {
var obj = {
name: k,
checked: null,
properties: null,
toggle: null
};
if(template[k] !== true) {
return convertRecurse(template[k], obj, k);
} else {
return obj;
}
}).then(function(obj_) {
$scope.propertyTemplate.push(obj_);
return obj_; // make obj_ available to the caller
});
}, $q.resolve()); // $q is assumed
}
function convertRecurse(array, obj, parent) {
var namespace = ...
return namespace.fetchProperties().then(function(props) {
var propArr = ... // some synchronous transform of (props)
var objArr = ... // some synchronous transform of (array, propArr)
// Build a .then() chain from `objArr`
return objArr.reduce(function(promise, o) {
return promise.then(function() {
if(o.subProperties) {
var propObj = {
name: o.property,
checked: null,
properties: null,
toggle: null
};
return convertRecurse(o.subProperties, propObj, o.property).then(function() {
propArr = ... // some synchronous transform of (propArr, propObj)
});
}
});
}, $q.resolve())
.then(function() {
obj.properties = propArr;
obj.toggle = true;
return obj; // deliver the augmented obj back to the caller.
});
}).catch(function(error) {
console.log(error);
throw error;
});
}
除了我自己的错误(根本不可能),您需要做的就是重新插入三个转换的代码,为了整体流程的清晰,省略了这三个转换的代码。就个人而言,我会将变换写为函数,并将代码保持原样。