2016-04-01 10 views
0

ich lernen, wie Knoten und ECMAScript 6.Promise.all in Node.js stellt nicht die Funktion dann

Ziel meiner Skript zu verwenden ist, eine Liste von PNG-Dateien in einem Verzeichnis umbenennen. Ich möchte nur die PNG-Dateien umbenennen (es gibt auch JPG) und am Ende die Anzahl der umbenannten Dateien anzeigen. Aufgrund der nicht blockierenden Natur von Node ist es nicht so offensichtlich und ich entschied mich, die Gelegenheit zu nutzen, ES6-Versprechen zu entdecken.

'use strict'; 

const fs = require('fs-extra'); 

const dir = '/Users/toto/Desktop/png/'; 
const suffix = '_IMAGE.'; 
const regex = /(.*)\.(png)$/; 
var nbFiles = 0; 

// Rename a png file with a suffix 
var renameFile = (filename) => { 
    return new Promise((resolve, reject) => { 
     if(regex.test(filename)){ 
     let newFileName = filename.replace(regex, '$1' + suffix + '$2'); 
     fs.rename(dir + filename, dir + newFileName, (err) => { 
      let msg = filename + ' => ' + newFileName; 

      if (err) { 
      console.log('KO : rename of ' + msg); 
      reject(err); 
      } 

      console.log('OK : rename of ' + msg); 
      resolve(nbFiles++); 
     }); 
     } 
    }); 
}; 

// Read files in a directory and call renameFile + display number of files renamed 
fs.readdir(dir, (err, files) => { 
    if(err) return console.error(err); 

    var promise = Promise.all(
     files.map(renameFile) 
    ).then(function(nb){ 
     console.log('Number of files renamed : ', nb); 
    }).catch(function(err){ 
     console.log('Error ', err); 
    }); 
}); 

Das erwartete Ergebnis ist, dass Dateien umbenannt werden und die Nachricht Anzahl der umbenannten Dateien angezeigt wird.

Ich bekomme Dateien umbenannt, aber ich kann keine Nachricht (der dann oder der Catch-Aufruf) sehen. Irgendwas stimmt nicht, aber Debug-Sessions können mir nicht helfen.

Danke für jede Hilfe!

PS: Meine Umgebung ist Knoten 5.10 und OS X 10.11.

+0

Sie sollten wirklich auf der niedrigst möglichen Ebene promisfy - nur ein Versprechen für 'fs.rename' und nichts anderes - keine Logik, keine Protokolle erstellen. Ihr Problem besteht darin, dass Ihr Versprechen niemals gelöst wird, wenn die "Regex" nicht übereinstimmt. – Bergi

Antwort

2

Das Problem ist, dass Sie einige Versprechen erstellen, die für immer ausstehend bleiben (werden nie aufgelöst): wenn die regex nicht mit der filename übereinstimmt. Die Promise.all wird auf sie warten - auf unbestimmte Zeit.

Sie sollten immer promisify auf der niedrigsten möglichen Ebene - in Ihrem Fall fs.rename und fs.readdir - und keinen anderen Code innerhalb dieser Funktion, die sich mit der "alten" Callback-API beschäftigt. Keine Anwendungslogik, keine String-Verkettung, keine Protokollierung, nichts.

function rename(from, to) { 
    return new Promise((resolve, reject) => { 
     fs.rename(from, to, (err, res) => { 
      if (err) reject(err); 
      else resolve(res); 
     }); 
    }); 
} 
function readdir(from, to) { 
    return new Promise((resolve, reject) => { 
     fs.readdir(from, to, (err, res) => { 
      if (err) reject(err); 
      else resolve(res); 
     }); 
    }); 
} 

(Wenn das sich wiederholende scheint - es ist - schreiben eine Hilfsfunktion, oder die man von einem Versprechen Bibliothek verwenden)

Mit denen können Sie jetzt richtig (und einfacher) implementieren Ihr Skript:

const dir = '/Users/toto/Desktop/png/'; 
const suffix = '_IMAGE.'; 
const regex = /(.*)\.(png)$/; 
readdir(dir).then(files => 
    Promise.all(files.map(filename => ({ 
     from: dir + filename, 
     to: dir + filename.replace(regex, '$1' + suffix + '$2') 
    })).filter(r => r.from != r.to).map(r => { 
     let msg = r.from + " => " + r.to; 
     return rename(r.from, r.to).then(() => { 
      console.log("OK: " + msg); 
     }, err => { 
      console.log("KO: " + msg); 
      throw err; 
     }); 
    })); 
).then(function(res) { 
    console.log('Number of files renamed : ', res.length); 
}).catch(function(err) { 
    console.error('Error ', err); 
}); 
+0

interessanter Code! Ich mag auch die Tatsache, dass Sie das imperative Muster des 1. Tests der Regex vermeiden und 2. etw. Ersetzen. Stattdessen filtern Sie die Dateien aus, die "in sich selbst umbenannt werden" würden. –

+0

Dies ist ein wirklich guter Code und viel einfacher zu verstehen, was passiert. – Wainage

+0

Danke Bergi für Ihre schnelle und elegante Antwort! Ich verstehe, dass es besser ist, auf der niedrigsten Ebene zu promiifizieren. Meine Funktion renameFile hat zu viel gemacht (Regex Test + Umbenennen). Ich liebe, wie Sie ein anonymes Objekt (mit von und zu Eigenschaften) einführen, um es anschließend auf eine funktionale Weise zu verwenden. Ich denke noch nicht funktional genug. Ich denke, dass eine .catch() in Ihrem Code nach Rückkehr Renam fehlt. Kannst du @Bergi für die Leute in der Zukunft bearbeiten? – pom421

Verwandte Themen