Angularjs 动态嵌套的$resource承诺与有序的$q.all承诺

Angularjs 动态嵌套的$resource承诺与有序的$q.all承诺,angularjs,angular-promise,Angularjs,Angular Promise,第二次更新 我们正在实现一个BulkEdit功能,它向后端发送异步CRUD请求 因此,我在这里需要的是一组动态创建的嵌套承诺 在抽象版本中,数据数组可能如下所示: var objArr = [ { name: 'A', subs: [ { id: 1, _action: 'create' }, { id: 2, _action: '

第二次更新

我们正在实现一个BulkEdit功能,它向后端发送异步CRUD请求

因此,我在这里需要的是一组动态创建的嵌套承诺

在抽象版本中,数据数组可能如下所示:

   var objArr = [
    {
      name: 'A',
      subs: [
        {
          id: 1,
          _action: 'create'
        },
        {
          id: 2,
          _action: 'create'
        },
        {
          id: 3,
          _action: 'delete'
        }
      ]
    },
    {
      name: 'B',
      subs: [
        {
          id: 4,
          _action: 'create'
        },
        {
          id: 5,
          _action: 'put'
        }
      ]
    },
    {
      name: 'C',
      subs: []
    }
  ];
我试图说明应该如何按照“\u action”给出的顺序发送对该数据的请求

  • 获取一些事务ID(见下文)
  • 一旦存在事务ID,就开始根据以下规则发送对数组中每个对象的请求:

    • 每个对象一次发送所有“删除”请求(如果有)
    • 之后,或者如果没有任何“删除”请求,则发送所有“放置” 如果有的话,请求
    • 在“删除”和/或“放置”之后,发送所有“创建”请求(如果有)
  • 对某个对象的所有请求完成后,立即对每个对象执行某些操作

  • 完成所有对象后,立即关闭事务
  • 如何创建此动态嵌套/非嵌套的承诺链

    更新代码现在包含承诺创建

    调用下面的函数时,TransactionService首先获取每个请求都需要发送的事务id。当一切都成功时,交易将结束

    我目前的问题是承诺没有以正确的顺序解决(而选项飞行前请求似乎是),并且本示例创建承诺,即使它们不是必需的(例如,对于上面示例中的对象“C”)

    这是“提交”的函数:

     function submit(objArr, transactionId) {
    
      var promises = objArr.map(function (obj) {
        return submitWithTransId(transactionId, obj)
          .then(function (response) {
             // Object done
          });
      });
    
      return promises;
    }
    
    这个功能实际上是在创造承诺:

    function submitWithTransId(transactionId, obj) {
    
      var promisesDelete = [];
      var promisesUpdate = [];
      var promisesCreate = [];
    
      angular.forEach(obj['subs'], function (sub) {
    
          switch (sub._action) {
            case 'delete':
              promisesDelete.push(createPromise(sub, bulktransactionId));
              break;
            case 'put':
              promisesUpdate.push(createPromise(sub, bulktransactionId));
              break;
            case 'create':
              promisesCreate.push(createPromise(sub, bulktransactionId));
              break;
        }
      });
    
      var chainedPromises = $q.all(promisesDelete).then(function (deleteResponse) {
          return $q.all(promisesUpdate).then(function (updateResponse) {
            return $q.all(promisesCreate).then(function (createResponse) {
            });
          });
        });
    
      return chainedPromises;
    
    这是我的
    createPromise
    函数:

    /** only simplified handling create case **/
    
    function createPromise(sub, bulktransactionId) {
    
    var queryParams = {};
    if (bulktransactionId !== undefined && bulktransactionId !== null) {
       queryParams.transaction_id = bulktransactionId;
    }
    
    var promise = MyResourceService.create(queryParams, sub).$promise;
    promise.then(function (newSub) {
        // do something with the new/updated/deleted sub, especially update view model
     });
     return promise;
    }
    
    /** MyResourceService **/
    return $resource(ENV.apiEndpoint + 'api/v1/subs/:_id',
     {
      _id: '@id'
     }, {
      create: {
       method: 'POST'
      }
     }
    );
    

    您可以看看下面的解决方案。目的是为您提供某种结构。请看,您将不得不修改您的使用

     var objArr = [{
            name: 'A',
            subs: [{
                    id: 1,
                    _action: 'create'
                },
                {
                    id: 2,
                    _action: 'create'
                },
                {
                    id: 3,
                    _action: 'delete'
                }
            ]
        },
        {
            name: 'B',
            subs: [{
                    id: 4,
                    _action: 'create'
                },
                {
                    id: 5,
                    _action: 'put'
                }
            ]
        },
        {
            name: 'C',
            subs: []
        }
    ];
    
    
    
    var promises = objArr.map(function(obj) {
        return firstLevelPromise(obj)
            .then(function(response) {
                console.log(response); // promise for each object
                return response;
            });
    });
    
    $q.all(promises)
        .then(function(response) {
            console.log(response); // completion - close transaction
        });
    
    
    function firstLevelPromise(obj) {
        var deletePromises = [];
        var putPromies = [];
        var insertPromies = [];
    
        obj.subs.forEach(function(sub) { // Preparing promises array for delete, put and insert
            if (sub._action === "delete") {
                deletePromises.push(deletePromise(sub));
            } else if (sub._action === "put") {
                putPromies.push(putPromise(sub));
            } else {
                insertPromies.push(insertPromise(sub));
            }
        });
    
        return $q.all(deletePromises) // executing delete promises
        .then(function(deleteResponse) {
            console.log("deleteExecuted: " + obj.name);
            return $q.all(putPromies) // on completion of delete, execute put promies
                .then(function(putResponse) {
                    console.log("putExecuted: " + obj.name);
                    return $q.all(insertPromies) // on completion of put, execute insert promises
                        .then(function(insertResponse) {
                            console.log("insertExecuted: " + obj.name);
                            return "object promise completed: " + obj.name; // on completion, return
                        });
                });
        });
    }
    
    function deletePromise(task) {
        return $q.resolve(task); // write your delete code here
    }
    
    function putPromise(task) {
        return $q.resolve(task); // write your put code here
    }
    
    function insertPromise(task) {
        return $q.resolve(task); // write your insert code here
    }
    
    请注意,上述代码将执行以下操作

    • 准备承诺集合,其中objectArray中的每个对象都有一个承诺
    • 每个承诺都有一个承诺链,即删除承诺,然后是put承诺,最后是insert承诺,即它确保每个对象执行删除任务,然后在完成时执行put任务,然后在完成时执行insert任务
    这是一个用于

    更新

    问题仅在于
    createPromise
    函数。将代码更新为以下内容。问题是您在返回之前调用了
    ,然后调用了
    ,因此,您很可能返回了一个已解决的承诺,如
    $q.resolve()
    。在这种情况下,
    create
    请求可能在
    delete
    put
    之前得到解决,而
    put
    调用可能在
    delete
    之前得到解决。因此,您应该从这里返回承诺,并在
    $q.all
    块中执行操作后的操作

    function createPromise(sub, bulktransactionId) {
    
        var queryParams = {};
        if (bulktransactionId !== undefined && bulktransactionId !== null) {
           queryParams.transaction_id = bulktransactionId;
        }
        return MyResourceService.create(queryParams, sub).$promise;
    }
    

    试试这个-诀窍是累积承诺(这就是我使用
    reduce
    的目的。希望它能有所帮助

    // reversed the order => delete actions first; otherwise you may have to do extra logic may be needed
    var objArr = [ 
       { name: 'A', 
         subs: [
            { id: null,
              _action: 'delete'
            }, 
            { id: 2,
              _action: 'create']
            }
       },
       { name: 'B',
         subs: [
            { id: 3.
              _action: 'create'
            }
         ]
     ];
    
     Promise.all(objArr.map(obj => {
       return obj.subs.reduce((accumulatedPromisedSub, sub) => {
         return accumulatedPromisedSub.then(_ => yourRequestCallHere(sub) )
       },
       Promise.resolve(true) // you could also do your delete here if you like
       )
     }))
    
    // OR going sort order agnostic:
    
     Promise.all(objArr.map(obj => {
       const deleteAction = obj.subs.find(sub => sub._action === 'delete');
    
       return obj.subs.reduce((accumulatedPromisedSub, sub) => {
         if (sub._action === 'delete') return accumulatedPromisedSub;
         return accumulatedPromisedSub.then(_ => yourRequestCallHere(sub) )
       },
       deleteAction ? yourRequestCall(deleteAction) : Promise.resolve(true)
       )
     }))
    

    我很高兴也很感激,我找到了它

    据我所知,我的代码中有两个主要问题

    因为
    $resource
    没有提供(请原谅我,专业人士!)真实的
    $promise
    即使我使用类似
    .get()。$promise
    的东西,我也不得不这样做

  • 使用
    bind
    createPromise函数映射到我的数组
  • 仅在返回
    $q.all
    承诺之前直接进行映射
  • 在任何其他情况下,
    $resource
    似乎立即用一个空对象来填充它的承诺,
    $q。所有的
    都不再有效,因为承诺看起来像是解决了问题

    特别感谢@nikhil,他支持我找到了这个丑陋复杂的东西,并赢得了赏金

    这是工作片段:

    function submitWithTransId(transactionId, obj) {
    
     var arrayDelete = [];
     var arrayUpdate = [];
     var arrayCreate = [];
    
     angular.forEach(obj['subs'], function (sub) {
    
       switch (sub._action) {
         case 'delete':
           arrayDelete.push(sub);
           break;
         case 'update':
           arrayUpdate.push(sub);
           break;
         case 'create':
           arrayCreate.push(sub);
           break;
        }
     });
    
     var promisesDelete = flattenArray(arrayDelete.map(createPromise.bind(undefined, obj, transactionId)));
    
     return $q.all(promisesDelete).then(function (deleteResponse) {
    
        console.log('Delete Promises ' + obj.name + ' resolved');
    
        var promisesUpdate = flattenArray(arrayUpdate.map(createPromise.bind(undefined, obj, transactionId)));
    
        return $q.all(promisesUpdate).then(function (updateResponse) {
          var promisesCreate = flattenArray(arrayCreate.map(createPromise.bind(undefined, obj, transactionId)));
    
          console.log('Update Promises ' + obj.name + ' resolved');
    
          return $q.all(promisesCreate).then(function (createResponse) {
    
            console.log('Create Promises ' + obj.name + ' resolved');
    
          });
        });
      }).catch(function (error) {
        console.log('Catched an error: ');
        console.log(error);
      });
    

    }))

    你能把它分成两个数组,然后首先处理所有的删除,当所有的承诺都完成后,再处理其余的吗?也许可以构建两个承诺数组,一个用于创建,一个用于删除。然后你可以做一些像Promise.all(deletes).Then(function(){Promise.all(creates);}(是的,我可以这样做,但是它不是“每个对象”执行的,它是引导某个对象“一个”完成的过程:-(@LBA)你可以构建一个包含它们自己的承诺数组的对象数组。@BrianGlaz,你可能是对的,但这正是我作为一个主要使用PHP的人被卡住的地方:-(我真的在尝试理解并将其应用到我的代码中。目前没有任何成功。但我会进一步尝试。好的。如果你在某个地方遇到困难,请告诉我。谢谢,如果我正确理解了你的问题,你的解决方案是为每个“操作”创建承诺,而不是为每个“操作”创建每个“对象”,我会再次更新我的问题,尝试更加精确。@LBA)-那么它似乎是正确的,直到并且除非
    createPromise
    函数中出现了一些问题。请您也添加
    createPromise
    函数好吗?我同意@nikhil。OP用于填充
    promisesDelete
    promisesUpdate
    createPromise>函数肯定存在一些问题nd
    promisesCreate
    数组。另外,@LBA在调用它时如何引用
    bulktransactionId
    ?它不应该是
    transactionId
    function submitWithTransId(transactionId, obj) {
    
     var arrayDelete = [];
     var arrayUpdate = [];
     var arrayCreate = [];
    
     angular.forEach(obj['subs'], function (sub) {
    
       switch (sub._action) {
         case 'delete':
           arrayDelete.push(sub);
           break;
         case 'update':
           arrayUpdate.push(sub);
           break;
         case 'create':
           arrayCreate.push(sub);
           break;
        }
     });
    
     var promisesDelete = flattenArray(arrayDelete.map(createPromise.bind(undefined, obj, transactionId)));
    
     return $q.all(promisesDelete).then(function (deleteResponse) {
    
        console.log('Delete Promises ' + obj.name + ' resolved');
    
        var promisesUpdate = flattenArray(arrayUpdate.map(createPromise.bind(undefined, obj, transactionId)));
    
        return $q.all(promisesUpdate).then(function (updateResponse) {
          var promisesCreate = flattenArray(arrayCreate.map(createPromise.bind(undefined, obj, transactionId)));
    
          console.log('Update Promises ' + obj.name + ' resolved');
    
          return $q.all(promisesCreate).then(function (createResponse) {
    
            console.log('Create Promises ' + obj.name + ' resolved');
    
          });
        });
      }).catch(function (error) {
        console.log('Catched an error: ');
        console.log(error);
      });