2017-02-15 2 views
0

Ich habe ein Versprechen innerhalb eines anderen Versprechen wie folgt aussehen verschachtelt:Promises aus, um

adb.screencap(list, id).then(function(missing) { 
    adb.getScreens(list, id).then(function() { 
     res.render('screencap', {output: "Screens captured."}) 
    }) 
}) 

Wo adb.screencap und adb.getScreens ist:

adb.screencap = function(list, id){ 
    return new Promise(function (resolve, reject) { 
     var array = new Array(); 
     var promises = new Array(); 

     for (var i = 0; i < list.length; i++) { 
      var cmd = "adb -s " + list[i] + " shell screencap /sdcard/" + list[i] + "-" + id + ".png"; 
      var missing = new Array(); 

      console.log("== " + cmd); 
      promises.push(adb.openArray(i, array, list, cmd, missing)); 
     } 
     Promise.all(promises).then(function (missing) { 
      console.log(("resolve")); 
      resolve(missing); 
     }) 
    }) 
} 
adb.getScreens = function(list, id){ 
    return new Promise(function (resolve, reject){ 
     for (var i = 0; i < list.length; i++) { 
      var cmd = 'adb -s ' + list[i] + ' pull /sdcard/' + list[i] + "-" + id + ".png /home/IdeaProjects/DeviceServer/public/files/" + list[i] + "-" + id + ".png"; 
      exec(cmd, function (err, stdout, stderr) { 
       console.log(stdout); 
       console.log(cmd); 
      }); 
     } 
     resolve(); 
    }) 
} 

Gibt es einen Grund, warum die adb.getScreens Versprechen wird abgeschlossen, bevor das adb.screencap-Versprechen gegeben wird?

+0

Ah die Freude der Versprechen :) Ich kann keine direkte Hilfe bieten, da es meinem Gehirn weh tut, aber es gibt einen nützlichen Link [https://developers.google.com/web/fundamentals/getting-started/primers/ Versprechungen] – DaveOz

+0

Das ist unmöglich. Der Callback, der den Aufruf von 'adb.getScreens' enthält, wird nur ausgeführt * nachdem *' adb.screencap' aufgelöst wurde. Bitte geben Sie mehr (oder genauere) Informationen zu diesem Problem an. Was lässt dich glauben, dass ein Versprechen vor dem anderen endet? –

+0

FWIW, erstellen Sie kein neues Versprechen in 'adb.screencap' (' neues Versprechen (...); ') zurück, nur' return Promise.all (...) '. –

Antwort

0

Verspricht Ihr adb.openArray Versprechen zurück? Dann funktioniert nur Promise.all.

Und Sie sollten das Versprechen von getScreens innerhalb des Rückrufs lösen, wenn exec. Es ist draußen und wartet nicht darauf, dass Exec beendet wird.

1

Ich versuche immer noch herauszufinden, was schief läuft, da es ziemlich merkwürdig erscheint. Es ist wahrscheinlich irgendwo in der openArray() - Methode oder in der exec() -Funktion.

Für das, was es wert ist, einige Dinge vereinfachen können, wie Felix vorschlagen:

// If the getScreens handler doesn't need the 'missing' returned from screencap 
adb.screencap(list, id).then(function(missing) { 
    return adb.getScreens(list, id); 
}).then(function (gottenScreens) { 
    res.render('screencap', {output: "Screens captured."}) 
}); 

// You can just return the Promise.all here instead of adding another promise 
// just to resolve the outer one. 
adb.screencap = function(list, id) { 
    var array = new Array(); 
    var promises = new Array(); 
    for (var i = 0; i < list.length; i++) { 
     var cmd = "adb -s " + list[i] + " shell screencap /sdcard/" + list[i] + "-" + id + ".png"; 
     var missing = new Array(); 

     console.log("== " + cmd); 
     // is this some async operation or are you just creating all the commands here? 
     // if so, it does't make sense to use a promise here. 
     promises.push(adb.openArray(i, array, list, cmd, missing)); 
    }  
    return Promise.all(promises); 
} 
+0

Beziehen Sie sich darauf: 'Versprechungen.Push (adb.openArray (i, Array, Liste, cmd, fehlt));'? Hier ist adb.openArray ein Versprechen und ich versuche, es für jedes Element in der Liste auszuführen. – rrain

1

Sie lösen getScreens(), bevor einer der exec() Anrufe innerhalb sie abgeschlossen haben. Sie sind asynchron. Sie enden irgendwann später, aber Sie rufen resolve() direkt nachdem Sie alle gestartet haben. Sie versuchen also zu rendern, bevor eines der Ergebnisse, die Sie rendern müssen, verfügbar ist.

Stattdessen müssen Sie exec() selbst promitisten und dann diese Versprechen in einem Array sammeln und Promise.all() verwenden, um zu sehen, wenn alle von ihnen erledigt sind. Nur dann wird getScreens() tatsächlich fertig sein.

Es gibt viele andere Probleme auch hier. screencap() verwendet ein Anti-Pattern. Sie brauchen hier kein eigenes Versprechen zu formulieren. Sie können einfach das Versprechen von Promise.all() zurückgeben, und die Verwendung dieses Anti-Patterns führt dazu, dass Sie alle Fehler verlieren, die von einem der Versprechen ausgelöst werden.

Hier ist eine Empfehlung:

// promisify exec 
function execP(cmd) { 
    return new Promise(function(resolve, reject) { 
     exec(cmd, function(err, stdout, stderr) { 
      if (err) return reject(err); 
      console.log(cmd); 
      console.log(stdout); 
      console.log(stderr); 
      resolve({stdout: stdout, stderr: stderr}); 
     }); 
    }); 
} 

adb.getScreens = function(list, id){ 
    return Promise.all(list.map(function(item) { 
     var cmd = 'adb -s ' + item + ' pull /sdcard/' + item + "-" + id + ".png /home/IdeaProjects/DeviceServer/public/files/" + item + "-" + id + ".png"; 
     return execP(cmd); 
    })); 
} 

Jetzt .getScreens() gibt ein Versprechen, das nur gelöst werden, wenn alle exec() Anrufe gemacht werden (so Ihre Ausgabedateien für Ihre redner verfügbar und bereit sein).

Dies konfiguriert .getScreens(), um zu einem Array von Objekten aufzulösen, die die Informationen stdout, stderr von allen Ihren Exec-Aufrufen enthält. Es scheint nicht, dass Sie versuchen, diese Ausgabe trotzdem zu verwenden, aber so ist dies konfiguriert.