2017-02-11 15 views
0

Я использую пакет [ssh2-sftp-client] [1] для рекурсивного чтения всех каталогов внутри данного удаленного пути.Как определить, когда завершены несколько асинхронных вызовов для нескольких массивов в Node.js

Вот код.

const argv = require('yargs').argv; 
const client = require('ssh-sftp-client'); 
const server = new Client(); 
const auth = { 
    host: '192.168.1.11', 
    username: argv.u, 
    password: argv.p 
}; 

const serverRoot = '/sites/'; 
const siteName = 'webmaster.com'; 

// list of directories on the server will be pushed to this array 
const serverPaths = []; 

server.connect(auth).then(() => { 
    console.log(`connected to ${auth.host} as ${auth.username}`); 
}).catch((err) => { 
    if (err) throw err; 
}); 

server.list('/sites/').then((dirs) => { 
    redursiveDirectorySearch(dirs, `${serverRoot}${siteName}/`); 
}) 
.catch((err) => { 
    if (err) throw err; 
}); 

function recursiveDirectorySearch(dirs, prevPath) { 
    let paths = dirs.filter((dir) => { 
    // returns directories only 
     return dir.type === 'd'; 
    }); 

    if (paths.length > 0) { 
     paths.forEach((path) => { 
      server 
       .list(`${prevPath}${path.name}`) 
       .then((dirs) => { 
        console.log(`${prevPath}${path.name}`); 
        recursiveDirectorySearch(dirs, `${prevPath}${path.name}`); 
        serverPaths.push(`${prevPath}${path.name}`); 
       }) 
     } 
    } 
} 

На первом, подключение будет производиться на сервере, а затем перечислить все, что под «/ сайтов /» каталога, который будет затем быть передан в функцию «recursiveDirectorySearch». Эта функция получит массив того, что находится в каталоге '/ sites /' на сервере, в качестве первого параметра, который будет отфильтрован, так что у него будут только каталоги. Если найден один или несколько каталогов, вызов сервера для каждого каталога в массиве будет сделан для того, чтобы получить все в разделе «/ sites/'+» имя каталога в массиве ». Эта же функция будет снова вызвана тем, что возвращается вызовом на сервер, пока не будет найден другой каталог.

Всякий раз, когда каталог найден, его имя в строке будет перенесено в массив «serverPaths». Насколько я могу судить, этот поиск работает и успешно выдвигает все имена каталогов в массив.

Однако я не могу придумать способ обнаружения, когда этот рекурсивный поиск для всех каталогов завершен, поэтому я могу что-то сделать с массивом «serverPaths».

Я попытался использовать Promise.all(), но не знаю, как его использовать, когда количество вызовов функций неизвестно.

ответ

0

Вы просто не хватает пару return с, добавить Promise.all, и Array#map и вы сделали

Примечание: не используется Promise.all на serverPaths, а, используя тот факт, что возвращающую обещание в .then приведет к Promise, который возвращается .then берет на обещание, которое возвращается (хммм, что не очень хорошо объяснил, это, но это обещает 101 вещи на самом деле!

server.list('/sites/').then((dirs) => { 
    // added a return here 
    return recursiveDirectorySearch(dirs, `${serverRoot}${siteName}/`); 
}) 
.then(() => { 
    // everything is done at this point, 
    // serverPaths should be complete 
}) 
.catch((err) => { 
    if (err) throw err; 
}); 

function recursiveDirectorySearch(dirs, prevPath) { 
    let paths = dirs.filter((dir) => { 
    // returns directories only 
     return dir.type === 'd'; 
    }); 
    // added a return, Promise.all and changed forEach to map 
    return Promise.all(paths.map((path) => { 
     //added a return here 
     return server 
      .list(`${prevPath}${path.name}`) 
      .then((dirs) => { 
       console.log(`${prevPath}${path.name}`); 
       // swapped the next two lines 
       serverPaths.push(`${prevPath}${path.name}`); 
       // added a return here, push the path before 
       return recursiveDirectorySearch(dirs, `${prevPath}${path.name}`); 
      }) 
    })); 
} 
+0

Я пытался изменения код таким образом, чтобы значение 'value' передавалось в' .then', где все сделано, это массив «serverPaths» таким образом, что вам даже не нужен массив 'serverPaths', но я как-то потерялся: p Это должно быть возможно, но я просто не с это достаточно сегодня! –

0

Одна из главных вещей, которая выпрыгивает на меня, - это ваше первоначальное утверждение if. (если paths.length> 0) {run recursion} Кажется, что это действительно хорошо работает для первого вызова, потому что вы знаете, что возвращаемые данные будут заполнены массивом, полным каталогов.

Ваша функция, однако, не имеет логики, построенной для массива длиной 0. В этом случае вы сможете получить все имена каталогов, которые вы ищете. Представлено таким образом, который вы ищете. Это также означает, что ваши призывы к более высоким частям дерева никогда не смогут разрешить.

Попробуйте добавить логику для обработки случаев для массива с длиной нуля | if (paths.length === 0) return; | Это было бы сложным выходом из рекурсивных вызовов в более высоких частях стека.