Добавить элементы в уже оцененный цикл - PullRequest
0 голосов
/ 28 января 2020

Добрый день, я столкнулся со следующей проблемой, я пытаюсь l oop через список с подкаталогами добавить в массив (репозитории) маршруты этих подкаталогов, это мой код:

        for (n=0; n<=pendingRepos.length; n++){

        subruta = pendingRepos[pendingRepos.length -1]
           pendingRepos.pop()                   
            c.list(subruta, function(err, sublist) {
            if (sublist.length != 0){         
                for (g=0; g < sublist.length; g++){

                if (sublist[g].type === 'd' ){
                    repositories.push(subruta+'/'+sublist[g].name)
                    pendingRepos.push(subruta+'/'+sublist[g].name)
                    }      

                else {files.push(subruta+'/'+sublist[g].name)}                       
                }

            }

            });   

        }

Например, при запуске l oop для моего массива pendingRepos имеет следующую структуру:

pendingRepos = ['/ dir1 / dir2', / dir3 / dir4 ']

l oop выполняется правильно 2 раза и последний элемент был удален, но при время другого l oop для добавления другого «последнего» элемента в массив первый для l oop не учитывает его. Я понимаю, что условие уже оценивалось до того, как я добавил больше элементов, это правильно? Как я могу избежать этого?

1 Ответ

1 голос
/ 28 января 2020

Похоже, вы рассматриваете массив ожидающих репо двумя противоречивыми способами. Внешний для l oop:

for (n = 0; n <= pendingRepos.length; n++) { ... }

обрабатывает pendingRepos как неизменный список, проходя от начала до конца и обрабатывая каждый элемент. (И делать это неправильно тоже - мы должны итерировать до n < pendingRepos.length, если мы используем эту опцию).

Лог c сразу после l oop, однако

subruta = pendingRepos[pendingRepos.length -1]
pendingRepos.pop()

обрабатывает pendingRepos как изменяемый стек, из которого вы будете продолжать обрабатывать последний элемент, пока стек не будет пустым.

Чтобы правильно обработать массив, вам нужно выбрать один или другой. Поскольку кажется, что остальная часть вашего кода правильно использует подход стека, значение l oop в верхней части должно быть изменено для соответствия, что в этом случае будет просто

while (pendingRepos.length > 0) { ... }

Конечный результат будет выглядит следующим образом:

while (pendingRepos.length > 0){
    const subruta = pendingRepos[pendingRepos.length -1]
    pendingRepos.pop()                   
    c.list(subruta, function(err, sublist) {
        if (sublist.length != 0){         
            for (let g = 0; g < sublist.length; g++){
                if (sublist[g].type === 'd' ){
                    repositories.push(subruta+'/'+sublist[g].name)
                    pendingRepos.push(subruta+'/'+sublist[g].name)
                } else {
                    files.push(subruta+'/'+sublist[g].name)
                }
            }
        }
    });
}

РЕДАКТИРОВАТЬ: Приведенный выше ответ работает только в том случае, если c.list() является синхронной функцией, которая немедленно запускает ваш обратный вызов перед возвратом - однако, поскольку это связаться с FTP-сервером, это не так. Это означает, что все while l oop завершится sh до запуска любого из этих обратных вызовов, и все, что они добавят к pendingRepos, не будет обработано. Чтобы использовать асинхронные функции, вы должны структурировать свою функцию совершенно по-разному, в основном используя все больше и больше асинхронных функций, насколько это возможно. go.

К счастью, сделать это довольно легко в этом случае. То, что вы делаете с pendingRepos, концептуально известно как поиск в глубину (или «DFS») , где вы выполняете поиск по древовидной структуре, повторяя поиск на каждом подузле. Использование стека ожидающих каталогов является одним из способов создания DFS, а другой способ сделать это - использовать рекурсивную функцию (в основном повторяя функцию поиска каждый раз, когда вы достигаете каталога).

Вот возможная реализация что с использованием обратных вызовов, расширяющих весь путь.

// an outer function for the whole operation. You would provide
// a callback that takes the lists of repositories and files.
function getTheRepos(startList, callbackForWholeThing) {
    // build up our lists of repositories and files
    const repositories = [];
    const files = [];

    // keep track of how many calculations are running
    let repoGetCount = 0;

    // an inner function to run exactly one result
    function getOneRepo(subruta) {
        // at the start, say we're running
        repoGetCount++;
        c.list(subruta, function(err, sublist) {
            if (sublist.length != 0){         
                for (let g = 0; g < sublist.length; g++){

                if (sublist[g].type === 'd' ){
                    repositories.push(subruta+'/'+sublist[g].name)
                    // for each directory we find, call this inner function again.
                    // This is the critical part that makes this all work.
                    getOneRepo(subruta+'/'+sublist[g].name)
                } else {
                    files.push(subruta+'/'+sublist[g].name)
                }
            }
            // at the end, say we're not running,
            // and call the whole callback if we're the last one
            repoGetCount--;
            if (repoGetCount === 0) {
                callbackForWholeThing(repositories, files);
            }
        }
    });

    // now that we have the function, run it on each of our
    // start directories to start things off
    for (let n = 0; n < startList.length; n++) {
        getOneRepo(startList[n]);
    }

    // the cogs are in motion, so now return.
    // The callback will be called when the tree has been searched.
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...