2016-08-26 3 views
0

У меня есть функция рекурсивной функции для воссоздания/загрузки массива propertyTemplate.Рекурсивные обещания - иногда это работает, иногда это не

Первая функция задается объект так:

{ 
    staffedLocation: ['schedulingGroup',{property: 'staff',subProperties: ['description']}], 
    staff: true, 
    assignedShifts: true, 
    editedShifts: true, 
    deletedShifts: true, 
    unassignedShifts: true, 
    rangeStart: true, 
    rangeEnd: true 
} 

Мне нужно воссоздать этот объект в массив объектов таким образом, чтобы правильно заполнить мой интерфейс:

[ 
    {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"} 
] 

В настоящее время, когда я вызовите функцию преобразования, она проходит и начинает создавать мой массив объектов. Однако, когда он попадает на convertRecurse, создается обещание для сбора свойств для одного из элементов.

Первоначально я думал, что вложенность всего в рамках обещания приведет к правильной работе функции после того, как я соберу все свойства. Однако, когда я перехожу на страницу и загружаю шаблон в первый раз, свойства не отображаются. Если я снова заново запустил шаблон, он будет работать.

Я думал, что цепочка обещаний заставит второе обещание подождать, чтобы двигаться дальше. Однако у меня нет лучшего понимания того, как они работают.

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)); 
} 

Моя проблема в том, что когда я изначально называю эту функцию в первый раз, она не загружается.

enter image description here

Однако, если я называю его снова, кажется, что все работает отлично.

enter image description here

+0

'obj.properties = propArr;' Где 'obj'? – Katana314

+0

obj передается как часть параметров –

+0

Вне конвертацииRecurse, откуда вы знаете, когда установлено 'obj.properties'? (Обратите внимание, что он не будет установлен в тот момент, когда функция выйдет, поскольку обещание еще не завершено) – Katana314

ответ

1

Проблема у вас возникли проблемы асинхронного потока. Код в настоящее время обрабатывает convertRecurse() как синхронный, тогда как он фактически асинхронный.

Код трудно найти в местах, но хитроумные биты являются синхронными преобразованиями, которые я не пытался понять.

Исправления довольно обширны, отчасти потому, что асинхронные операции происходят в циклах. Более конкретно, вам нужно либо:

  • для выполнения асинхронных операций последовательно пути создания .then() цепи, или
  • для выполнения операций асинхронных параллельно и агрегатных обещаний

Как вы будете см. ниже, основным аспектом асинхронного потока является получение надлежащей отдачи.

Вот он, приняв последовательный подход:

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; 
    }); 
} 

Запрет ошибок с моей стороны (не совсем невозможно), все, что вам нужно сделать, это снова вставить код для трех преобразований, которые опущенными для ясность общего потока. Лично я бы написал преобразования как функции и сохранил код выше, чем он есть.

+0

Спасибо! Теперь все работает отлично! –

Смежные вопросы