Javascript обещает работать не так, как следует при использовании Promise.all - PullRequest
0 голосов
/ 03 июля 2018

У меня проблемы с некоторым кодом, когда я просто не могу понять, почему Обещания не работают так, как должны.

Функция, называемая "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 голосов
/ 03 июля 2018

Эти три функции:

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

переведет обещание на promises, которое затем следует ожидать Promise.all. Однако вы звоните Promise.all на promises, прежде чем позвонить этим трем, поэтому вы их не ждете. Чтобы решить эту проблему, просто отбросьте этот странный глобальный мутированный массив promises, просто верните обещания из ваших функций, поэтому вместо

promises.push(checkPathExists);

просто сделай:

    return checkPathExists;

Тогда в вашей функции start просто объедините их в цепочку:

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

dataset затем должен пройти через эту цепочку по тем же причинам promises - это плохо.

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