2017-12-09 1 views
2

ich ein Objekt habe wie so:Iterieren JavaScript-Objekt synchron

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

I durchläuft durch dieses Objekt und bei jeder Iteration: Ich mit der Datenbank verbinden, rufen Sie die Datei, ein paar Sachen tun und die Datei wieder speichern . Grundsätzlich asynchrones Zeug.

Jetzt stellt die DoStuff-Funktion sicher, dass ich einen lokalen Bereich habe, so dass es keine Inkonsistenzen gibt. Trotzdem ist die Ausführung aufgrund der asynchronen Operationen innerhalb jeder Schleife nicht synchron. Ich brauche im Grunde eine db, um vollständig verarbeitet zu werden, bevor ich zum nächsten übergehe. Wie behebe ich das?

Ein Ansatz, an den ich dachte, war eine rekursive Schleife. Aber nach meinem Verständnis würde dies erfordern, dass ich meine Datenstruktur umfassend ändere, was suboptimales imo ist.

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]); 
} 
} 
+0

@leaf Sie können eine serielle Versprechen Kette aus einem Array erstellen Rekursion oder Array.prototype.reduce verwenden. Ich habe als Antwort hinzugefügt. – HMR

+0

Möchten Sie die Datenbanken in einer bestimmten Reihenfolge bearbeiten? – leaf

+0

@leaf die Bestellung spielt keine Rolle – fsociety

Antwort

0

Das Promise-Objekt repräsentiert den eventuellen Abschluss (oder Fehler) einer asynchronen Operation und den daraus resultierenden Wert. Sie können versuchen wie.

$("#myPara").delay(4500).fadeOut().promise().done(function(){ 
 
    \t \t $("#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>

for (let prop in myObject) { 
    if (myObject.hasOwnProperty(prop)) { 
     var stuff= doStuff(prop, myObject[prop]).promise().done(function(){ 
     // Do whatever u want after completion of doStuff 
    }); 
    } 
    } 

Have a look at Mozila ref.

+1

OP tut dies bereits, aber das ist auch jetzt nicht synchron, der nächste doStuff-Aufruf würde ausgeführt werden, bevor dies abgeschlossen ist . – ayushgp

+0

Er möchte die nächste Iteration stoppen, bis doStuff nicht fertig ist – vibhor1997a

1

Sie könnten die Lösung, die Sie am Ende vorgeschlagen Object.entries(obj) mit verwenden. Zum Beispiel

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

Innen doStuff:

function doStuff(props, callback) { 
    // Process props 
    //finally in the promise of async call, on success call 
    .then(callback) 
} 

oder Sie können eine Generatorfunktion verwenden, wenn Sie for ... in Schleife verwenden möchten.

+0

Sie könnten Rekursion verwenden, aber keine Notwendigkeit, doStruff zu ändern, lassen Sie einfach die Prozessfunktion Rekursion anwenden. Wenn Prozess sowohl Schlüssel als auch Array hat, können Sie abgelehnte Versprechen verarbeiten (wissen, welche Taste zurückgewiesen wurde) und aufgelaufene Werte ansammeln. Ich denke, der einfachste Weg ist, das Array auf ein Versprechen zu reduzieren. Beide Methoden in meiner Antwort hinzugefügt, aber ohne Fehlerbehandler (einer lehnt ab, alles danach wird nie verarbeitet) und der Wert wird ignoriert. – HMR

1

Eine Lösung wäre, doStuff eine zurückgeben, die Sie verwenden können, um eine Kette von Versprechen mit Hilfe von Calls zu then aufzubauen.

Die Bluebird-Promise-Bibliothek bietet diese Funktionalität mit .each und .mapSeries.

Sie implementieren könnte es als:

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

Sie würde es so verwenden:

Promise.forEachSeries(arr, doStuff); 
2

Im Folgenden wird das tun, was Sie fragen, es gibt ein Array von resolve Werte.

Möchten Sie die Verarbeitung stoppen, wenn eine von ihnen ablehnt?Für den Fall, müssen Sie einige Änderungen vornehmen, jetzt lehnt sie ab, wenn einer von ihnen ablehnen und verarbeiten sie Schlüssel in Ihrem Objekt nicht fortgesetzt werden (Objekt mit dem Namen myObject):

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

Die Antwort ayushgp Rekursion verwendet, hier ist ein funktionierendes Beispiel, dass keine Änderungen an doSomething benötigt:

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

1

Der folgende Code entspricht möglicherweise dem, wonach Sie fragen. Ich benutze Indizes i und j eine Schleife durch Datenbanken und Dateien bzw.  :

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