Я знаю, что этот вопрос почти такой же, как этот: Порядок исполнения обещаний, но может ли кто-нибудь объяснить мне, в чем моя ошибка? У меня есть следующие функции:
// 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() функция должна возвращать обещание. Как я могу это сделать?
Ваш searchForImportFolder работает асинхронно, но не возвращает обещание. Таким образом, следующий then выполняется немедленно с возвращаемым значением searchForImportFolder, которым является undefined, потому что ничего не было возвращено; trueDestPath установлен на какое-то время в будущем, игнорируется и печально.
@MohamedAshiff - async / await здесь не поможет, пока не будет исправлена фундаментальная проблема с searchForImportFolder.
Вы также можете цепь свои обещания.
@lependu - OP является связывает свои обещания.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


searchForImportFolder не возвращает обещание, поэтому цепочка не ждет завершения этого обещания. Сделайте то же самое в searchForImportFolder, что и в checkFolderExistence: заключите API в стиле обратного вызова в обещание.
Пара замечаний:
checkFolderExistence должен вызывать reject в пути ошибки; в настоящее время этого не происходит.promisify, которую вы можете использовать для обертывания вызовов API в стиле обратного вызова в обещаниях, вместо того, чтобы делать это вручную. Или вы можете использовать promisify-fsnpm модуль, или promisifynpm модуль, который позволяет вам обещать весь API сразу, или собственный экспериментальный API обещаний для fs узла.checkFolderContent асинхронным (снова используя обещания), а не использовать readdirSync, который задерживает основной поток, ожидающий ввода-вывода.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;
Поиск будет производиться только один раз.
@Amadan - Хорошая ссылка. Также есть собственный обещает API для fs Node, но он все еще экспериментальный.
используйте async await для поддержания порядка выполнения скрипта