Bonjour,

J'ai deux méthodes, une qui retourne l'arborescence d'un dossier _getDirectoryTree et une autre qui retourne les informations d'un fichier _getFile. Cette dernière fait un appel à une base de donnée avec Sequelize. Voici la première méthode :

static _getDirectoryTree(url) {
    let dir = this._getDirectory(url);
    dir.children = {};

    const dirData = this._safeReadDirSync(dir.path);

    if (dirData !== null) {
        dir.children = dirData.map(child => {
            const stats = fs.statSync(_path.join(dir.path, child));
            if (stats.isDirectory()) {
                return this._getDirectory(url + '/' + child);
            }
            else {
                this._getFile(url + '/' + child, stats, (err, file) => {
                    if (err) return err;
                    else
                        return file;
                });
            }
        });
    }
    console.log('ha');

    return dir;
}

Et voici la seconde :

static _getFile(url, stats, cb) {
    if (!stats) return undefined;
    const path = _path.join(this.root, url);
    const path_parsed = _path.parse(path);

    db.File.findOne({where: {path: path}, include: ['owner', 'group']})
        .then(file => {
            file.type = 'file';
            file.url = this.url + url;
            file.base = path_parsed.base;
            file.name = path_parsed.name;
            file.ext = path_parsed.ext;
            file.size = stats.size;
            file.mime = mime.lookup(path_parsed.ext);

            console.log('got');
            return cb(null, file);
        })
        .catch(err => {
            return cb(err);
        });
}

Séparément, les deux méthodes fonctionnent très bien. Mais ensemble, c'est la cata dû au côté asynchrone de Node JS. En effet, j'ai ajouté deux console.log() dans les méthodes que vous voyez au dessus. Et il se trouve que je vois d'abord ha et ensuite got alors que je devrais voir got puis ha. Voici le résultat que je souhaiterai obtienir :

{
    "type": "directory",
    "name": "bar",
    "url": "https://192.168.50.5:8080/storage/bar",
    "path": "storage/bar",
    "children": [
        {
            "type": "file",
            "id": 1,
            "path": "storage/bar/foo.txt",
            "ownerId": 1,
            "groupId": null,
            "createdAt": "2017-10-06T00:00:00.000Z",
            "updatedAt": "2017-10-06T00:00:00.000Z",
            "owner": {
                "id": 1,
                "username": "groot",
                "email": "groot@local.dev",
                "password": "$2a$10$qz8OmVUNB4zgf96keFGPWOjM5mb1QhjrbxR.zzz1dtNUadOAlQmBq",
                "createdAt": "2017-10-06T14:56:30.000Z",
                "updatedAt": "2017-10-06T14:56:30.000Z"
            },
            "group": null,
            "base": "foo.txt",
            "name": "foo",
            "ext": ".txt",
            "size": 0,
            "mime": "text/plain"
        },
        {
            "type": "directory",
            "name": "fooBar",
            "url": "https://192.168.50.5:8080/storage/bar/fooBar",
            "path": "storage/bar/fooBar"
        },
        {
            "type": "directory",
            "name": "me",
            "url": "https://192.168.50.5:8080/storage/bar/me",
            "path": "storage/bar/me"
        }
    ]
}

Le fichier du dossier est bien présent. Or moi j'obtient :

{
    "type": "directory",
    "name": "bar",
    "url": "https://192.168.50.5:8080/storage/bar",
    "path": "storage/bar",
    "children": [
        null,
        {
            "type": "directory",
            "name": "fooBar",
            "url": "https://192.168.50.5:8080/storage/bar/fooBar",
            "path": "storage/bar/fooBar"
        },
        {
            "type": "directory",
            "name": "me",
            "url": "https://192.168.50.5:8080/storage/bar/me",
            "path": "storage/bar/me"
        }
    ]
}

J'ai null à la place de mon fichier parce que Node n'a pas attendu le résultat de _getFile. Il a retourné l'objet sans. Le truc c'est que je vois mal comment contourner ce problème à l'intérieur d'une fonction map. Est-ce que quelqu'un pourrait m'aider ? Car j'ai une autre méthode _getDirectory (qui me donne des informations relatives au dossier) qui ne fait pas d'appel à la base de donnée du coup je n'ai pas ce soucis d'attendre non ?

Merci et bonne journée ! :)

2 réponses


utilise les Promise sur ta premiere methode comme ca l'ors de sont appel tu peut utiliser le .then() pour passer la 2eme methode en callback et du coup elle se fera apres la fin de la premiere methode. les Promises rendent le code synchrone en gros.

Wizix
Auteur

Comme conseillé, j'ai utilisé les Promise sur mes méthodes. J'obtiens toujours le même soucis sur cette la méthode _getDirectoryTree(bon ça a résolu pas mal de mes autres problèmes, donc excellent conseil !). Je pense que le soucis vient du fait que j'utilise des Promise embriquées dans une fonction map. Il faudrait que j'utilise Promise.all() à mon avis mais j'ai pas réussi à le faire. Voici ce que j'ai pour le moment :

static _getDirectoryTree(url) {
        return new Promise(resolve => {
            Storage._getDirectory(url)
                .then(dir => {
                    dir.children = {};

                    Storage._safeReadDir(dir.path)
                        .then(dirData => {
                            if (dirData !== null) {
                                dir.children = dirData.map(child => {
                                    const child_url = url + '/' + child;

                                    Storage._getStats(child_url)
                                        .then(stats => {
                                            if (stats.isDirectory()) {
                                                Storage._getDirectory(child_url)
                                                    .then(directory => directory);
                                            }
                                            else {
                                                Storage._getFile(child_url, stats)
                                                    .then(file => file);
                                            }
                                        });
                                });
                            }
                        })
                        .then(() => {
                            console.log('returning the dir');
                            return resolve(dir);
                        });
                });
        });
    };

Dans ma méthode _getDirectory et _getFile, j'ai placé les commandes suivantes console.log('Directory ready') et console.log('File ready'). Quand je fais ma requête, j'obtient :

Directory ready
returning the dir
Directory ready
Directory ready
File ready

Je vous ai fait un gist avec toute ma classe ici : gist

Merci pour votre aide ! :)