同步迭代javascript对象

时间:2017-12-09 04:49:37

标签: javascript loops asynchronous promise synchronization

我有一个像这样的对象:

let myObject = {
'db1': [db1_file1Id,db1_file2Id,db_1file3Id],
'db2': [db2_file1Id, db2_file2Id]
...
}

我遍历这个对象和每次迭代:我连接到数据库,检索文件,做一些事情并保存文件。基本上是异步的东西。

  for (let prop in myObject) {
    if (myObject.hasOwnProperty(prop)) {
      doStuff(prop, myObject[prop]);
    }
  }

现在doStuff函数确保我有一个本地范围,因此没有不一致。但是,由于每个循环内部的异步操作,执行不同步。我基本上需要一个db才能完全处理,然后继续下一个。我该如何解决这个问题?

我想到的一种方法是使用递归循环。但根据我的理解,这将要求我广泛地改变我的数据结构,这是次优的imo。

let arr; //containing my data

process(x) {
 if (x < arr.length){
   //process(x+1) is called inside doStuff after asynchronous operations are complete
   doStuff(arr[x]);
 }
}

5 个答案:

答案 0 :(得分:2)

以下将按您的要求执行,它会返回一组解析值。

如果其中任何一个拒绝,你想停止处理吗?如果您需要进行一些更改,现在拒绝其中任何一个更改并拒绝继续处理它们在您的对象中的键(名为myObject的对象):

&#13;
&#13;
var myObject = {
  'one': ["one"],
  'two': ["two"]
};
var doStuff = arr =>
  console.log("starting:", arr[0]) ||
  Promise.resolve(arr[0]);

var [promise,result] = 
  Object.keys(myObject)
    .reduce(
      ([promise,results], key) =>
        [
          promise
          .then(
            resolve =>
              doStuff(myObject[key])
          )
          .then(
            resolve => results.push(resolve)&&resolve
          )
          .then(
            resolve => console.log("done:", resolve)
          )
          ,results
        ]
      , [Promise.resolve(), []]
    )
promise.then(
  _ => {
    console.log("done all",result)
  }
);
&#13;
&#13;
&#13;

答案ayushgp使用递归,这是一个不需要做任何改变的工作示例:

&#13;
&#13;
var myObject = {
  'one': ["one"],
  'two': ["two"]
};
var doStuff = arr =>
  console.log("starting:",arr[0]) ||
  Promise.resolve(arr[0])

var process = (arr,processFn) => {
  const rec = (arr,processFn,promise,results) =>
    arr.length === 0
      ? promise.then(_=>results)
      : promise
        .then(_ => processFn(arr[0][1]))
        .then(result=>results.push(result)&&console.log("resolved:",result))
        .then(_ => rec(arr.slice(1),processFn,promise,results));
  return rec(arr,processFn,Promise.resolve(),[]);
};
process(
  Object.keys(myObject).map(key=>[key,myObject[key]]),
  doStuff
)
.then(
  results => console.log("done all, results:",results)
);
&#13;
&#13;
&#13;

答案 1 :(得分:1)

您可以使用{"value":["name","height","weight"],"done":false}最后提出的解决方案。例如,

Object.entries(obj)

在doStuff里面:

let arrProps = Object.entries(myObject);

process(index) {
 if (index < arrProps.length){
   // Call the callback once you complete execution of doStuff
   doStuff(arrProps[index], () => process(index + 1));
 }
}

如果你想使用function doStuff(props, callback) { // Process props //finally in the promise of async call, on success call .then(callback) } 循环,你可以使用生成器函数。

答案 2 :(得分:1)

一种解决方案是让doStuff返回Promise,您可以使用then调用来构建一连串的承诺。

Bluebird promise库通过.each.mapSeries提供此功能。

您可以将其实现为:

Promise.forEachSeries = function(array, action) {
  return array.reduce(function(prevPromise, value, index, array) {
    return prevPromise.then(function() {
      return action(value, index, array);
    });
  }, Promise.resolve());
}

您可以这样使用它:

Promise.forEachSeries(arr, doStuff);

答案 3 :(得分:1)

以下代码可能与您要求的内容相近。我使用索引ij分别遍历数据库和文件:

var dbs = {
  db1: ["q", "w", "e", "r"],
  db2: ["t", "y"]
};

var names = Object.keys(dbs);
var db, x, i = 0, j = 0;

if (names.length > 0) {
  db = dbs[names[i]];
  x = db[j];
  console.log("start");
  asyncProcessing(x)
  .then(onSuccess)
  .catch(onFailure);
}

function onFailure (e) {
  console.log("[FAILURE]", e);
  console.log("end");
}

function onSuccess (xx) {
  console.log("[SUCCESS]", xx);
  j = (j + 1) % db.length; // next j
  if (j === 0) i = i + 1; // next i
  if (i < names.length) {
    db = dbs[names[i]];
    x = db[j];
    asyncProcessing(x)
    .then(onSuccess)
    .catch(onFailure);
  } else {
    console.log("end");
  }
}

function asyncProcessing (x) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      // force first two success then random
      if (x === "q" || x === "w" || Math.random() * 3 > 1) {
        resolve(x + x);
      } else {
        reject("Not lucky. Try again.");
      }
    }, 1000);
  });
}

答案 4 :(得分:0)

Promise对象表示异步操作的最终完成(或失败)及其结果值。你可以试试。

addr = "......IP address is 2001:0000:3238:DFE1:63::FEFB. SUbnet mask is.........."
$("#myPara").delay(4500).fadeOut().promise().done(function(){
 		  $("#myHeading").attr("style","display:none;")  ;
      for(var i=10;i<15;i++){
      console.log(i);
      }
});
console.log("Hello promise !");

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="myPara"> Hello </p>
<h1 id="myHeading">to be hide</h1>

Have a look at Mozila ref.