2016-12-08 3 views
-1

ich mit diesem Code mich entschieden:Javascript Versprechen Chaining - seltsames Verhalten

var http = require('http'); 
var fs = require('fs'); 

function getFullPath(file){ 
    return new Promise(function(resolve, reject){ 
     fs.realpath(file, function(err, path){ 
      resolve(path); 
     }); 
    }); 
} 

function getFileSize(file){ 
    return new Promise(function(resolve, reject){ 
     fs.stat(file, function(err, stats){ 
      resolve(stats.size); 
     }); 
    }); 
} 

function calculateSize(files){ 
    var size = 0; 
    var files_count = files.length-1; 

    return new Promise(function(resolve, reject){ 
     files.forEach(function(file, i){ 
      getFullPath(file).then(getFileSize).then(function(tempSize){ 
       size += tempSize; 
       console.log(file, tempSize); 
       if(files_count == i){ 
        resolve(size); 
       } 
      }); 
     }); 
    }); 
} 

function getFiles(path){ 

    console.warn('Staring path:',path); 

    return new Promise(function(resolve, reject){ 
     fs.readdir(path, function(err, files){ 

      if(err || !files){ 
       reject(err); 
      } else { 
       resolve(files); 
      } 
     }); 
    }); 
} 

getFiles('/home/galio/DEV/js-sandbox').then(function(result){ 
    return calculateSize(result); 
}, function(err){ 
    console.log('ERROR:', err); 
}).then(function(size){ 
    console.log('All files size is: ', size); 
}); 

ich es mit Knoten v 6.9.1 leite, Folge davon ist:

.eslintrc.json 528 
.git 4096 
.gitignore 26 
README 0 
callbacks.js 1402 
functions-1.js 530 
functions-2.js 564 
functions-3.js 1798 
functions-4.js 737 
functions-5.js 1045 
All files size is: 10726 

So weit, so gut. Aber manchmal, vielleicht 1 von 10 run ich erhielt:

.eslintrc.json 528 
.git 4096 
.gitignore 26 
README 0 
functions-1.js 530 
callbacks.js 1402 
functions-2.js 564 
functions-3.js 1798 
functions-5.js 1045 
All files size is: 9989 
functions-4.js 737 

Beachten Sie, wie manchmal das Endergebnis vor der eigentlichen Schleife beendet ausgeführt wird. Warum? Ich kann das selbst nicht lösen und ich brauche Hilfe, um zu erkennen, was diesen Fehler ausmacht.

P.S. Die Datei, die unten geht, ist nicht immer 4.js-Funktionen.

Pls helfen

+0

Nicht ganz sicher, ob ich es richtig verstehe. Aber sollte 'calculateSize' nicht eine Reihe von Versprechen, eine für jede Datei, zurückgeben? Oder Sie müssen die Schleife in dieser Methode anders behandeln. Ich bin mir ziemlich sicher, dass es in dieser Schleife eine Wettlaufsituation gibt. Ich persönlich würde wahrscheinlich eine Reihe von Versprechen, eine für jede Datei, zurückgeben. Edit: Zu einem anderen Hinweis würde ich die Pfeilfunktion verwenden, da du bereits ES6 verwendest (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions) – Coxer

Antwort

3

Sie wahrscheinlich Promise#all in Ihrer Funktion calculateSize(files) verwenden sollten, wenn Sie lösen wollen, wenn alle Berechnungen für die Dateien fertig sind.

function calculateSize(files) { 
    return Promise.all(files.map(function (file) { 
     return getFullPath(file).then(getFileSize).then(function(size) { 
       console.log(file, size) 
       return size 
      }) 
     }) 
    }).then(function (sizes) { 
     return sizes.reduce(function (a, b) { 
      return a + b 
     }) 
    }) 
} 

Sie könnten sogar die Funktion machen eine Reihe von Dateien in einer Reihe von Größen Karte durch die endgültige then Rückruf zu entfernen.

+0

Nicht "if (files_count == i) "verhindern, dass das Versprechen erfüllt wird, bis alle Dateien summiert sind? –

+0

Es könnte sein, aber diese Logik schien mir verwirrend und verwirrender Code neigt dazu, subtile Fehler zu erzeugen. Ich würde OP eher zeigen, wie man 'Array # map' und' Promise # all' verwendet, um dieselbe Funktionalität in einer Weise zu implementieren, die die Komplexität reduziert. – gyre

+0

Definitiv das Problem gelöst. Vielen Dank! Ich werde mehr in Promise.all und Array.map einarbeiten müssen. – linderman

0

Ich glaube, Ihre zweite then wartet nicht auf calculateSize().

Versuchen Sie, dieses

getFiles('/home/galio/DEV/js-sandbox').then(function(result){ 
    calculateSize(result).then(function(size){ 
    console.log('All files size is: ', size); 
    } 
}, 
function(err){ console.log('ERROR:', err); } 
); 
1

ich Ihre eigene promisification gegen Wegrollen empfehlen würde, das ist mühsam und fehleranfällig. Lassen Sie eine Bibliothek wie bluebird dies für Sie tun.

Zusammen mit den anderen Merkmalen drossel Angebote, wie Implementierungen von .map() und .reduce(), können Sie Ihren Code so einfach gemacht werden und geradlinig wie folgt aus:

var Promise = require('bluebird'); 
var path = require('path'); 
var fs = Promise.promisifyAll(require('fs')); 

function calculateSizeAsync(dir) { 
    return fs.readdirAsync(dir) 
     .map(file => path.join(dir, file)) 
     .map(filepath => fs.statAsync(filepath)) 
     .reduce((total, stats) => {return total + stats.size}, 0); 
} 

calculateSizeAsync('/home/galio/DEV/js-sandbox') 
    .then(totalSize => console.log('All files size is: ' + totalSize)) 
    .catch(err => console.error('ERROR:', err)); 
+0

Außer dass er es nicht tat. Keine seiner handrollen Funktionen haben eine ordnungsgemäße Fehlerbehandlung. Es ist wirklich besser, eine getestete Bibliothek die Arbeit machen zu lassen. – Tomalak

Verwandte Themen