Рекурсивная функция JavaScript продолжает выполняться после возврата

#javascript #recursion #frontend #callstack #web-frontend

#javascript #рекурсия #интерфейс #стек вызовов #веб-интерфейс #callstack

Вопрос:

Я пытаюсь создать функцию JavaScript, которая рекурсивно ищет файл / каталог в файловой структуре и возвращает этот файл, если он найден. Это пример файловой структуры:

 var fileStructure = [
  {'pictures': ['picture1.png', {'beach': ['picture2.png']}]},
  {'videos': ['video1.mov', 'video2.mov']}
]
  

В словарях ключ представляет имя каталога, а значение представляет содержимое каталога. Каждый элемент в массивах является файлами. Итак, если я вызвал findFile('picture1.png') , я должен получить true, или если я вызываю findFile('videos') , я также должен получить true. Вот что у меня есть на данный момент:

 var fileStructure = [{ "music": [{ "acoustic": ["vlad-gluschenko-stars-extended.mp3"] }, { "chinese": ["AlbumArtSmall.jpg", "Folder.jpg", "keys-of-moon-yugen.mp3"] }, { "lofi": ["le-gang-relax-man.mp3", "purple-cat-field-of-fireflies.mp3"] }] }, { "sounds": [{ "campfire": ["fire-crackle.mp3", "fire-rumble.mp3"] }, { "rain": ["rain-heavy.mp3", "rain-light.mp3", "rain-tapping.mp3"] }, { "thunderstorm": ["thunderstorm.mp3"] }, { "wind": ["wind-base.mp3", "wind-howling.mp3", "wind-rattling.mp3"] }] }]

function findFile(fileName, dir) {
    for (i in dir) {
        let entry = dir[i];

        // If entry is a dictionary, unpack into array
        if (entry.constructor == Object) {
            // If the file being searched for is itself a directory
            if (Object.keys(entry).indexOf(fileName) != -1) {
                // !!!!! THIS PRINTS BUT THE FUNCTION KEEPS RUNNING !!!!!
                console.log(`Found directory: ${fileName}`);
                return true;
            }
            entry = Object.values(entry);
        }

        // If entry is an array (meaning it is the contents of a directory)
        if (Array.isArray(entry)) {
            findFile(fileName, entry);
        }
        // Found file
        else if (entry == fileName) {
            return true;
        }
    }
    return false;
}

// 
fileExists = findFile('tets', fileStructure);
console.log("done", fileExists);

fileExists = findFile('lofi', fileStructure);
console.log("done", fileExists);  

В моем коде я вызвал эту функцию следующим образом: fileExists = findFile('lofi', audioLibrary); Если вы посмотрите на мой комментарий, окруженный восклицательными знаками, эта строка печатается как ожидалось, однако даже после возврата true функция продолжает выполняться и, в конечном счете, переменные FileExists оцениваются как false .

Почему цикл, похоже, продолжается даже после возврата?

Это то, что произошло, когда я добавил точку останова в строку возврата. Как вы можете видеть, цикл выполняется снова.

РЕДАКТИРОВАТЬ: добавлена файловая структура, которую я использую.

Комментарии:

1. ваш код работает нормально. запустите фрагмент кода в вашем вопросе. скорее всего, у вас одна и та же функция запущена в нескольких местах, но, как и здесь, она работает нормально.

2. Вы ничего не делаете с рекурсивным возвращаемым значением findFile . return Завершается только текущий вызов, а не весь стек вызовов.

3. Представьте, что рекурсивный вызов findFile вызовет любую другую функцию, ее возврат не должен завершать вашу функцию, верно? Здесь то же самое.

4. вы, вероятно, хотите return findFile(fileName, entry);

5. Я не уверен, почему моя функция будет выполняться в нескольких местах, кроме того, когда она вызывает саму себя. В моем случае я получаю вывод: «Найден каталог: lofi», и в этот момент я бы предположил, что FileExists будет иметь значение true. Однако функция продолжается (вероятно, вызывается каким-то образом в другом rplace), и FileExists имеет значение false.

Ответ №1:

Проблема заключалась в том, что я на самом деле не возвращался findFile(fileName, entry); , поэтому функция выполняла поиск только в одном каталоге, и фактической рекурсии не было (duh lol!) Чтобы решить эту проблему, я отслеживал все подкаталоги в текущем каталоге, в которых выполнялся поиск, с переменной directories . Затем, как только был проверен последний файл в искомом каталоге, если результаты не были найдены, он попытается выполнить поиск в каждом каталоге в directories массиве. Если бы ей удалось найти совпадение в любом каталоге, функция вернула бы true.

 fileStructure = [{ "music": [{ "acoustic": ["vlad-gluschenko-stars-extended.mp3"] }, { "chinese": ["AlbumArtSmall.jpg", "Folder.jpg", "keys-of-moon-yugen.mp3"] }, { "lofi": ["le-gang-relax-man.mp3", "purple-cat-field-of-fireflies.mp3"] }] }, { "sounds": [{ "campfire": ["fire-crackle.mp3", "fire-rumble.mp3"] }, { "rain": ["rain-heavy.mp3", "rain-light.mp3", "rain-tapping.mp3"] }, { "thunderstorm": ["thunderstorm.mp3"] }, { "wind": ["wind-base.mp3", "wind-howling.mp3", "wind-rattling.mp3"] }] }]

function findFile(fileName, dir) {
    var directories = [];
    for (i in dir) {
        let entry = dir[i];

        // If entry is a dictionary, unpack into array
        if (entry.constructor == Object) {
            // If the file being searched for is itself a directory, then search the dictionary for a directory with the name of fileName
            if (Object.keys(entry).indexOf(fileName) != -1) {
                return true;
            }
            entry = Object.values(entry);
        }

        // If entry is an array (meaning it is the inside of a directory)
        if (Array.isArray(entry)) {
            directories.push(entry);
        }
        else if (entry == fileName) {
            console.log('Found the file:');
            console.log(entry);
            return entry;
        }

        // If item is the last item in directory and no files have matched, begin to search each of the sub-directories
        if (i == dir.length - 1) {
            for (directory of directories) {
                if (findFile(fileName, directory)) {
                    return true;
                }
            }
        }
    }
    return false;
}

fileExists = findFile('foo', fileStructure);
console.log('done', fileExists);

fileExists = findFile('lofi', fileStructure);
console.log('done', fileExists);