Порядок выполнения скрипта с обещанием

Я знаю, что этот вопрос почти такой же, как этот: Порядок исполнения обещаний, но может ли кто-нибудь объяснить мне, в чем моя ошибка? У меня есть следующие функции:

// The main function
function startTesting() {
    console.info("--- Thanks! Testing is running... ---");
    checkFolderExistence(dirPath)
        .then(checkFolderContent)
        .then(searchForImportFolder)
        .then(connectToDB)
        .catch(err => console.error("*** ERROR *** " + err));
}

function checkFolderExistence(path) {
    console.info('--- Checking the folder "' + path + '" existence... ---');
    let promise = new Promise(function(resolve, reject) {
        fs.readdir(path, (err) => {
            if (err) {
                console.error('*** ERROR **** The folder "C:\\For_testing" doesn\'t exist. Testing is stopped!!! ***');
            } else {
                console.info("--- The folder \"C:\\For_testing\" exists... ---");
                resolve(path);
            };
        });
    });
    return promise;
}

function checkFolderContent(path) {
    console.info('--- Checking the folder "' + path + '" content... ---');
    filesArray = fs.readdirSync(path);
    if (filesArray.length == 0) {
        console.error('*** ERROR *** There are no any files in ' + path + '. Testing is stopped!!! ***');
    } else {
        console.info('--- The folder is checked. It contains the next files: ---');
        for(let i = 0; i < filesArray.length; i++) {
            console.info(filesArray[i]);
        }
    };
}

function searchForImportFolder() {
    console.info('--- Searching for ".../Import" folder... ---');
    fs.readdir(destFolderPath64, (err) => {
        if (err) {
            fs.readdir(destFolderPath32, (err) => {
                if (err) {
                    console.error('*** ERROR *** The folder ".../Import" was not found ***');
                } else {
                    console.info('--- The folder ".../Import" was successfully found... ---');
                    trueDestPath = destFolderPath32;
                }
            });
        } else {
            console.info('--- The folder "C:/Program Files (x86)/StoreLine/Office/Import" was successfully found... ---');
            trueDestPath = destFolderPath64;
        }
    });
}

function connectToDB() {
    console.info('--- Connecting to the database... ---');
    let pool = new sql.ConnectionPool(config);
    pool.connect()
        .then(pool => {
            console.info("--- Connected to the database! ---");
            readDB(pool)
                .then(function() {
                    console.info("--- All needed information from DB was successfully received ---");
            })
                 .catch(err => console.error("*** ERROR *** " + err));
        })
        .catch(err => {
            pool = new sql.ConnectionPool(configWithoutPassw);
            pool.connect()
                .then(pool => {
                    console.info("--- Connected to the database without the password! ---");
                    readDB(pool)
                        .then(function() {
                            console.info("--- All needed information from the DB was successfully received ---");
                        })
                        .catch(err => console.error("*** ERROR ***" + err));
                })
                .catch(err => {
                    console.error("*** ERROR *** Can't connect to the DB ***")
                    sql.close();
                });
        });
}

Мне нужен строгий порядок выполнения функций: checkFolderContent => searchForImportFolder => connectToDB.

Фактически, выполнение выглядит следующим образом: checkFolderContent выполняется полностью, затем searchForImportFolder начинает выполнение (я вижу строку «--- Поиск папки« ... / Импорт »... ---» в консоли), но верно после этого запускается connectToDB и появляется следующая строка «--- Подключение к базе ... ---». И после этой строки я вижу "--- Папка" ... / Import "была успешно найдена ... ---" из предыдущей функции.

Что я сделал не так? Я читал, что в .then() функция должна возвращать обещание. Как я могу это сделать?

используйте async await для поддержания порядка выполнения скрипта

MdAshiff 14.11.2018 10:01

Ваш searchForImportFolder работает асинхронно, но не возвращает обещание. Таким образом, следующий then выполняется немедленно с возвращаемым значением searchForImportFolder, которым является undefined, потому что ничего не было возвращено; trueDestPath установлен на какое-то время в будущем, игнорируется и печально.

Amadan 14.11.2018 10:03

@MohamedAshiff - async / await здесь не поможет, пока не будет исправлена ​​фундаментальная проблема с searchForImportFolder.

T.J. Crowder 14.11.2018 10:03

Вы также можете цепь свои обещания.

lependu 14.11.2018 10:03

@lependu - OP является связывает свои обещания.

T.J. Crowder 14.11.2018 10:04
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
5
46
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

searchForImportFolder не возвращает обещание, поэтому цепочка не ждет завершения этого обещания. Сделайте то же самое в searchForImportFolder, что и в checkFolderExistence: заключите API в стиле обратного вызова в обещание.

Пара замечаний:

  • checkFolderExistence должен вызывать reject в пути ошибки; в настоящее время этого не происходит.
  • Node предоставляет функцию promisify, которую вы можете использовать для обертывания вызовов API в стиле обратного вызова в обещаниях, вместо того, чтобы делать это вручную. Или вы можете использовать promisify-fsnpm модуль, или promisifynpm модуль, который позволяет вам обещать весь API сразу, или собственный экспериментальный API обещаний для fs узла.
  • Возможно, вы захотите сделать checkFolderContent асинхронным (снова используя обещания), а не использовать readdirSync, который задерживает основной поток, ожидающий ввода-вывода.
  • Если вы используете какую-либо последнюю версию Node, возможно, вы захотите переключиться на использование функций async и ключевого слова await, поскольку это позволяет вам писать логический поток, а не писать кучу обратных вызовов.
  • searchForImportFolder должен возвращение свой результат, а не устанавливать глобальный.

Так, например, вот checkFolderExistence и searchForImportFolder, использующие util.promisify (они предполагают, что searchForImportFolder должен возвращение своего результата, поэтому вам придется настроить код, используя его):

const { promisify } = require("util");

const readdirPromise = promisify(fs.readdir);

function checkFolderExistence(path) {
    console.info('--- Checking the folder "' + path + '" existence... ---');
    return readdirPromise(path)
        .then(path => {
            console.info("--- The folder \"C:\\For_testing\" exists... ---");
            return path;
        })
        .catch(error => {
            console.error('*** ERROR **** The folder "C:\\For_testing" doesn\'t exist. Testing is stopped!!! ***');
        });
}

// ...

function searchForImportFolder() {
    console.info('--- Searching for ".../Import" folder... ---');
    return readdirPromise(destFolderPath64)
        .then(() => {
            console.info('--- The folder "C:/Program Files (x86)/StoreLine/Office/Import" was successfully found... ---');
            return destFolderPath64;
        })
        .catch(() => readdirPromise(destFolderPath32))
        .then(() => {
            console.info('--- The folder ".../Import" was successfully found... ---');
            return destFolderPath32;
        })
        .catch(error => {
            console.error('*** ERROR *** The folder ".../Import" was not found ***');
            throw error;
        });
}

Если вам не нужна вся эта регистрация, checkFolderExistence просто становится readdirPromise, а searchForImportFolder становится:

Или, если вам не нужна вся эта регистрация (предположительно, для отладки):

const { promisify } = require("util");

const readdirPromise = promisify(fs.readdir);

// ...

function searchForImportFolder() {
    console.info('--- Searching for ".../Import" folder... ---');
    return readdirPromise(destFolderPath64)
        .then(() => {
            return destFolderPath64;
        })
        .catch(() => readdirPromise(destFolderPath32));
}

А здесь они используют util.promisify и async / await:

Или используя util.promisify и async / await:

const { promisify } = require("util");

const readdirPromise = promisify(fs.readdir);

// ...

async function searchForImportFolder() {
    try {
        await readdirPromise(destFolderPath64);
        return destFolderPath64;
    } catch (error) {
        await readdirPromise(destFolderPath32);
        return destFolderPath32;
    }
}

Если вы хотите избежать многократного поиска двух разных папок, простая тактика - просто запомнить обещание от searchForImportFolder, а затем использовать then для него в любое время, когда вам понадобится это значение:

const importFolderPromise = searchForImportFolder();

... затем, когда вам это нужно:

importFolderPromise.then(folder => {/*...*/});

... или в функции async:

const folder = await importFolderPromise;

Поиск будет производиться только один раз.

Также есть promisify-fs, у которого уже есть обещания из коробки, как замена fs.

Amadan 14.11.2018 10:05

@Amadan - Хорошая ссылка. Также есть собственный обещает API для fs Node, но он все еще экспериментальный.

T.J. Crowder 14.11.2018 10:07

Другие вопросы по теме