Порядок выполнения скрипта с Promise - PullRequest
0 голосов
/ 14 ноября 2018

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

// 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 начинает выполнение (я вижу строку "--- Поиск папки" ... / Import "... ---" в консоли), но вернопосле этого connectToDB запускается и появляется следующая строка "--- Соединение с базой данных ... ---".И после этой строки я вижу "--- Папка" ... / Import "была успешно найдена ... ---" из предыдущей функции.

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

1 Ответ

0 голосов
/ 14 ноября 2018

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

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

  • checkFolderExistence должен вызвать reject на пути ошибки;в настоящее время это не так.
  • Узел предоставляет функцию promisify, которую можно использовать для оборачивания вызовов API в стиле обратного вызова в обещаниях, а не делать это вручную.Или вы можете использовать promisify-fs npm модуль или promisify npm модуль , который позволяет вам обещать весь API одновременно, или собственный Node экспериментальный 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 становится:

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

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;

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...