Javascript承诺使用Promise.all时不会按应有的方式工作

时间:2018-07-02 21:21:58

标签: javascript promise

当我无法找到Promise不能按应有的方式工作时,我在某些代码上遇到了问题。

名为“ start”的函数是调用所有其他函数的函数,因此都从那里开始。

功能在底部,使用以下命令执行:

start(filename);

到那里都可以,但是问题在于这些函数应该在Promise.all被处理之前全部完成执行(应该是最后一个)。

这不是正在发生的事情...发生的是Promise.all在所有功能完成其工作之前就已执行。

我只是找不到问题。

代码如下:

export default function createDataset(filename, callback) {

    const dataset = {};
    const promises = [];

    function setResults() {

        const checkPathExists = fs.access(possiblePath)
            .then(() => {
                dataset.results_fullpath = possiblePath;
            })
            .catch(() => {
                dataset.results_fullpath = '';
            });

        promises.push(checkPathExists);

        return checkPathExists;
    }

    function tree() {

        const checkCloudFileReadable = fs.access(cloudFilePath, fs.constants.R_OK)
            .then(() => {
                dataset.potreePointCloud = cloudFilePath;
            })
            .catch((err) => {
                dataset.potreePointCloud = '';
            });

        promises.push(checkCloudFileReadable);
    }


    function setLink() {

        const checkPathExists = fs.access(LinkPath)
            .then(() => fs.readFileSync(LinkPath, {'encoding': 'utf8'}))
            .catch(err => {
                // log error if not an expected error
                // error here

            });

        promises.push(checkPathExists);
    }


    function loadErrorText() {
        if (dataset.state === 'error') {
            const errorFilePath = path.join(dataset.path_parts.dir, `${dataset.path_parts.base}-report.txt`);

            dataset.error_file_path = errorFilePath;

            const readErrorFile = fs.readFile(errorFilePath, 'utf8')
                .then(errorData => {
                    dataset.error_text = errorData;
                })
                .catch(() => {
                    dataset.error_text = 'Cannot find error report';
                });

            promises.push(readErrorFile);
        }
    }

    function loadWarningText() {
        if (dataset.state === 'complete') {
            const warningFilePath = path.join(dataset.results_fullpath, 'warnings.txt');

            const readWarningFile = fs.readFile(warningFilePath, 'utf8')
                .then(warningData => {
                    dataset.warning_text = warningData;
                })
                .catch(() => {
                    dataset.warning_text = '';
                });

            promises.push(readWarningFile);
        }
    }


    function loadResultFiles(parentFolderContents) {
        dataset.result_files = [];

        const resultFileExtensions = ['ply'];
        const resultsFiles = parentFolderContents.filter(fileName => {
            const splitFilename = fileName.split('.');

            return splitFilename.length >= 2 &&
                resultFileExtensions.indexOf(splitFilename[splitFilename.length - 1]) !== -1;
        });

        dataset.result_files = resultsFiles;

        if (resultsFiles.indexOf('summary.txt') !== -1) {
            fs.readJson(path.join(dataset.results_fullpath, 'summary.txt'), (err, summaryObject) => {
                if (!err) {
                    dataset.summary = summaryObject;

                    if (summaryObject !== undefined && Object.prototype.hasOwnProperty.call(summaryObject, 'date_modified')) {
                        dataset.modified = new Date(summaryObject.date_modified);
                    }
                }
            });
        }
    }


    function check(parentFolderContents) {

        if (files.length >= 1) {
            // do stuff
        }
    }


    function start(fullpath) {

        const statPath = fs.stat(fullpath)
            .then(stat => {
                if (!Object.prototype.hasOwnProperty.call(dataset, 'modified')) {
                    dataset.modified = stat.mtime;
                }

                dataset.bytesize = stat.size;
            })
            .catch(() => {
                if (!Object.prototype.hasOwnProperty.call(dataset, 'modified')) {
                    dataset.modified = new Date(Date.now());
                }
            });

        promises.push(statPath);

        if (dataset.path_parts.base.startsWith('complete-')) {
            dataset.state = 'complete';
            dataset.name = dataset.path_parts.name.slice('complete-'.length);
            setResults()
                .then(() => {
                    setLink();
                    tree();
                    loadWarningText();

                    const readPath = fs.readdir(dataset.results_fullpath);

                    promises.push(readPath);

                    return readPath;
                })
                .then(folderContents => {
                    loadResultFiles(folderContents);
                    check(folderContents);
                });

        } else {
            dataset.name = dataset.path_parts.name;
        }

        dataset.key = dataset.name;
    }

    start(filename);

    Promise.all(promises)
        .then(() => {
            if (typeof callback === 'function') {
                callback(dataset);
            }
        });

    return dataset;
}

如何解决此问题以迫使Promise.all等到所有其他功能完成?

1 个答案:

答案 0 :(得分:1)

这三个功能:

setLink();
tree();
loadWarningText();

将对promises的承诺,然后应由Promise.all等待。但是,在调用这三个之前,请先在Promise.all上调用promises,因此不要等待它们。为了解决这个问题,只需要丢弃那个奇怪的全局变量promises数组,而只需从函数中返回promise,就可以代替

promises.push(checkPathExists);

只需:

    return checkPathExists;

然后在您的start函数中将它们链接起来:

setResults()
  .then(() => Promise.all([
      setLink(),
      tree(),
      loadWarningText()
  ])).then(() => fs.readdir(dataset.results_fullpath))
  .then(/*...*/)

dataset应该出于同样的原因通过该链传递,promises不好。