【问题标题】:Order of script execution with PromisePromise 的脚本执行顺序
【发布时间】:2018-11-14 17:21:11
【问题描述】:

我知道这个问题与这个问题几乎相同:Execution order of Promises 但有人可以向我解释我的错误在哪里吗? 我有下一个功能:

// 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 开始执行(我可以看到行“--- Searching for ".../Import" folder... --- “在控制台中),但紧接着connectToDB 开始并出现下一行“--- Connecting to the database... ---”。在该行之后,我从上一个函数中看到“--- 成功找到文件夹“.../Import”... ---”。

我做错了什么?我读过.then() 函数应该返回一个承诺。我该怎么做?

【问题讨论】:

  • 使用异步等待来维护脚本执行的顺序
  • 您的searchForImportFolder 是异步的,但不返回承诺。因此,下一个then 立即执行,返回值为searchForImportFolder,即undefined,因为没有返回任何内容; trueDestPath 被设定在未来的某个时间,被忽视和悲伤。
  • @MohamedAshiff - async/awaitsearchForImportFolder 的基本问题得到解决之前将无济于事。
  • 你也可以chain你的承诺。
  • @lependu - OP 正在兑现他的承诺。

标签: javascript node.js promise


【解决方案1】:

searchForImportFolder 不返回承诺,因此链不会等待该承诺完成。在searchForImportFolder 中执行与在checkFolderExistence 中相同的操作:将回调样式的API 包装在一个promise 中。

几点说明:

  • checkFolderExistence 应该在错误路径中调用reject;目前没有。
  • Node 提供了一个promisify 函数,您可以使用该函数将回调样式的 API 调用包装在 Promise 中,而不是手动执行。或者你可以使用promisify-fs npm module,或promisify npm module,让你一次性承诺整个API,或者Node自己的experimental promises API for fs
  • 您可能希望使 checkFolderContent 异步(再次使用 Promise)而不是使用 readdirSync,后者会阻止主线程等待 I/O。
  • 如果您使用的是任何最新版本的 Node,您可能希望切换到使用 async 函数和 await 关键字,因为它可以让您编写逻辑流程而不是编写一堆回调。李>
  • searchForImportFolder 应该返回它的结果,而不是设置一个全局的。

例如,这里是 checkFolderExistencesearchForImportFolder 使用 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.promisifyasync/await

或者使用util.promisifyasync/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 - 良好的链接。还有 Node 自己的 promises API for fs,但仍处于试验阶段。
猜你喜欢
  • 2016-08-07
  • 2020-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-26
相关资源
最近更新 更多