使用unshift和pop序列处理对象数组

时间:2016-09-28 04:45:33

标签: javascript angularjs arrays

我有一个数组,我在其中推送对象,我使用array.unshift(object)将对象添加到数组的开头。

我正在使用var object = array.pop()从数组中检索元素,这是从数组末尾删除对象。

现在我的数组很快就被填满了,这个数组中的多个对象每秒都被推送。每当一个新元素被推入数组时,我需要弹出数组并处理它并进一步发送,这需要时间。

这是在每次间隔1秒后调用方法然后从数组中弹出一个元素并处理它的好方法,但是如果从数组处理对象需要1秒以上,那么接下来对进程方法的调用也应该被延迟,简而言之,进程数组方法应该在每个时间间隔之后调用,但是如果先前的调用仍在处理中则应该等待。

实施它的更好方法是什么?

示例代码:

angular.module('myApp')
.service('DataService', ['$rootScope', 'UpdateService', function($rootScope, UpdateService)
{
    // To store array of JSON updates    
    var arrayOfUpdates = [];

    // To store callbacks to which we need to send updates after processing 
    var arrayofCallbacks = [];

    // Method is getting called when there are updates from "UpdateService" server 
    this.onDataUpdated = function (jsonObj)
    {
        // This will add this object in the array
        arrayOfUpdates.unshift(jsonObj);
    }

    // This method will process data and send it further 
    function processData()
    {
         // Get the last element from the array 
         var jsonObj = arrayOfUpdates.pop();

         // Now process this JSON data  
         var data = doSomeCalculations(jsonObj); 

         // There can be 10-20 callbacks at a time   
         for(var index=0;index<arrayofCallbacks.length;index++)
         {
               var object = arrayofCallbacks[index]; 
               object.onUpdatedData(data);
         }       

         // After this pop next element and process and send to registered callbacks 
         // I can not call "processData()" again as it can create loop 
         // Also calling it after interval might call it when it has not completed processing 
    }
});

2 个答案:

答案 0 :(得分:1)

在我看来,你正在实施一个队列。您希望能够推送到队列的后面(unshift),这可能会很快发生。您还希望处理队列前面的项目(pop),但处理阶段需要时间。我的猜测是这些进程是异步操作的,所以你最终会在同一时间发生许多处理步骤,并且遇到一些类似于数据的条件。

除非您需要主动检查队列中的内容(处理函数之外),否则我建议一起删除队列,并使用promise chaining代替队列。

要做到这一点,无论何时触发传入数据事件,而不是使用unshift(),您只需将数据传递到您的承诺链,直到所有先前的处理完成后才会执行。一些伪js:

// the promise chain (initialised to automatically trigger then())
var worker = Promise.resolve();

// handle incoming data
function incomingData(data){
    // process this data AFTER all other processing and update the chain
    worker = worker.then(last => processData(data));
}

// process data
function processData(data){
    // do work on the data and return a promise if work is async
    return ...
}

更新:我建议的第一件事就是阅读Promises。但我会在下面做一个更深入的解释:

  1. 设置工作人员。通过将变量设置为Promise.resolve(),您实际上是在创建已经解决(已完成)的承诺。可以把它想象成一个空队列,完成了它需要完成的所有工作。

  2. 获取新的传入数据时更新承诺链。如果你把一个函数放在里面,就像myPromise.then(myFunc)一样,myFunc一直运行直到myPromise被解决,这取决于程序员。它可能会在一些api调用返回后或其他一些工作后解决。您可以按如下方式考虑对worker的更新:

    想象一下,每次新数据到达时都会运行processData(data),并传入收到的data。现在想象一下,在前一个函数完成之前无法运行该函数。这就是上面代码中发生的事情。所以是的,存储了传入的数据。

答案 1 :(得分:0)

假设你的任务时间是异步的,你可能会想出一个带有promises的递归异步流控制,如下所示;

我们每隔250毫秒将1到10之间的随机数移到arr数组,同时每1000毫秒弹出一个。定义的限制是10个项目,一旦我们达到limit值不移位停止。

&#13;
&#13;
function doStgAndPop(a){
  return new Promise((resolve,reject) => { var id = setTimeout(_ => a.length > 0 ? resolve(a.pop()) : reject(id),1000)});
}

function doStgAndUnshift(a){
  return new Promise((resolve,reject) => { var id = setTimeout(_ => a.length < limit ? (a.unshift(~~(Math.random()*10+1)),resolve(a))
                                                                                     : reject(id),250)});
}

function runnerPop(a){
  doStgAndPop(a).then(v => (console.log("pop out resulted:",v),runnerPop(a)))
                .catch(e => (console.log("array is now empty"),clearSetTimeout(e)));
}
function runnerUnshift(a){
  doStgAndUnshift(a).then(v => (console.log("new array after unshift",JSON.stringify(v)),runnerUnshift(a)))
                    .catch(e => (console.log("array limit:",limit,"reached"),clearSetTimeout(e)));
}

var limit = 10,
      arr = [];

runnerUnshift(arr);
runnerPop(arr);
&#13;
&#13;
&#13;

我使用的是原生的ES6承诺。 doStgAndPop返回一个promise并运行一个异步函数(setTimeout),该函数挂起1000毫秒并从arr弹出一个项目arr.length > 0或拒绝该操作。{{1} }非常相似,但每隔250毫秒取消一个项目,直到达到限制,一旦达到限制,它就会拒绝。 doStgAndUnshiftrunnerPop是递归函数,分别调用runnerUnshiftdoStgAndPop并接收承诺。在doStgAndUnshift阶段,我们递归调用转轮函数,并在then阶段完成操作。