等待对数组中每个项目的承诺

时间:2018-08-01 17:01:49

标签: javascript node.js promise

我正在Node中使用ssh2-sftp-client下载一系列文件。下载文件后,我需要检查每个文件是否为CSV,然后检查我的数据库以查看文件是否先前已导入。

我正在使用Promise,但在排序时遇到了麻烦。我认为经过几个小时的研究,我已经接近了,但不能完全理解。

代码如下:

const isFileCSV = (filename) => {

    return new Promise( (resolve, reject) => {
        if (filename.endsWith('.csv')) {
            result = 'true';
            resolve(result);
        } else {
            result = 'false';
            resolve(result);
        }
    });
}

const wasFileImported = (filename) => {     
    // Return a new promise
    return new Promise( (resolve, reject) => {
        // Core function
        con.query(`CALL wasFileImported('${filename}')`, (err, results) => {
            console.log('02 Checking if file was previously imported.');    
            if (err) {
                logEntry('error', `Error searching database: ${err}`);
                reject(Error('false'));
            } else {
                result = results[0][0]['importCheck'];
                resolve(result);
            }
        })
    });
}

const importFile = (file) => {
    isFileCSV(file).then((result) => {
        console.log(`01a File ${file} ends with csv? ${result}`);
        result = result.toLowerCase();
        return result;
    }).then((result) => {
        if (result === 'false') {
            console.log(`01b ${result} = Not csv, log it and skip to next.`);
            return;
        } else if (result === 'true') {
            console.log(`01b ${result} = It is csv, go to next step`);
            return result;
        }
    }).then((result) => {
        wasFileImported('file').then((result) => {
            console.log('03 checked import, result: ', result);
            return result.toLowerCase();
        }).then((result) => {
            switch(result) {
                case 'false':
                    console.log('04a download file and log it');
                    break;
                case 'true':
                    console.log('04b skip it and log the skip');
                    break;
                default:
                    console.log('04c unknown error, log the skip');                         
            }           
        })              
    })              
}

logEntry('info', `attempting to connnect to ${config.destination.host}`);
console.log('00 start');

sftp.connect(crmConfig).then(() => {
    logEntry('info', `connected to ${config.destination.host}`);
    return sftp.list(ordersUrl);
}).then((data) => {
    fileList = [];
    Object.entries(data).forEach(([key, val]) => {
        fileList.push(val['name']);
    });
    return fileList;
}).then((fileList) => {
    let promises = [];

    fileList.forEach((file) => {
        promises.push(importFile(file));
    });

    Promise.all(promises).then(function(results) {
        console.log('Done');
    }).catch(function(err) {
        console.log('Error');
    });
});

我希望看到的是以下内容:

00 start
01a File daily.csv ends with csv? true
01b true = It is csv, go to next step
02 Checking if file was previously imported.
03 checked import, result:  FALSE
04a download file and log it
01a File daily072418.csv ends with csv? true
01b true = It is csv, go to next step
02 Checking if file was previously imported.
03 checked import, result:  FALSE
04a download file and log it
01a File test.csw ends with csv? false
01b false = Not csv, log it and skip to next.
02 Checking if file was previously imported.
03 checked import, result:  FALSE
04a download file and log it
Done

我实际上得到的是:

00 start
01a File daily.csv ends with csv? true
01a File daily072418.csv ends with csv? true
01a File test.csw ends with csv? false
01b true = It is csv, go to next step
01b true = It is csv, go to next step
01b false = Not csv, log it and skip to next.
Done
02 Checking if file was previously imported.
03 checked import, result:  FALSE
04a download file and log it
02 Checking if file was previously imported.
03 checked import, result:  FALSE
04a download file and log it
02 Checking if file was previously imported.
03 checked import, result:  FALSE
04a download file and log it

早期版本未使用Promise.all,但仍产生相同的结果。我还尝试过更改解决方案以返回wasFileImported和isFileCSV,但是随后我只得到“ 00 Start”,然后是“ Done”,之间没有执行。

很明显,我没有按照我的意图正确地遍历数组。做所有事情都是按顺序完成的最好方法是什么?

编辑 对于其他需要它的人,这里是最终的工作代码,这要感谢@ jordan-peterson和@spakmad:

const isFileCSV = (filename) => {
    return new Promise( (resolve, reject) => {
        if (filename.endsWith('.csv')) {
            result = 'true';
            resolve(result);
        } else {
            result = 'false';
            resolve(result);
        }
    });
}

const wasFileImported = (filename) => {     
    // Return a new promise
    return new Promise( (resolve, reject) => {
        // Core function
        con.query(`CALL wasFileImported('${filename}')`, (err, results) => {
            console.log('02 Checking if file was previously imported.');    
            if (err) {
                logEntry('error', `Error searching database: ${err}`);
                reject(Error('false'));
            } else {
                result = results[0][0]['importCheck'];
                resolve(result);
            }
        })
    });
}

const importFile = (file) => {
    return isFileCSV(file).then((result) => {
        console.log(`01a File ${file} ends with csv? ${result}`);
        result = result.toLowerCase();
        return result;
    }).then((result) => {
        if (result === 'false') {
            console.log(`01b ${result} = Not csv, log it and skip to next.`);
            return;
        } else if (result === 'true') {
            console.log(`01b ${result} = It is csv, go to next step`);
            return result;
        }
    }).then((result) => {
        return wasFileImported('file').then((result) => {
            console.log('03 checked import, result: ', result);
            return result.toLowerCase();
        }).then((result) => {
            switch(result) {
                case 'false':
                    console.log('04a download file and log it');
                    break;
                case 'true':
                    console.log('04b skip it and log the skip');
                    break;
                default:
                    console.log('04c unknown error, log the skip');                         
            }           
        })              
    })              
}

console.log('00 start');

sftp.connect(crmConfig).then(() => {
    logEntry('info', `connected to ${config.destination.host}`);
    return sftp.list(ordersUrl);
}).then((data) => {
    fileList = [];
    Object.entries(data).forEach(([key, val]) => {
        fileList.push(val['name']);
    });
    return fileList;
}).then((fileList) => {
    let promiseChain = Promise.resolve()

    fileList.forEach((file) => {
        promiseChain = promiseChain.then(() => {
            return importFile(file)
        })
    })
});

3 个答案:

答案 0 :(得分:1)

您要连续三次调用importFile(一种异步方法),因此它会同时遍历这些方法。如果您要一个接一个地执行,我想做的就是这个。

let promiseChain = Promise.resolve()
myFiles.forEach((file) => {
   promiseChain = promiseChain.then(() => {
      return importFile(file)
   }
}

循环中的每次迭代都会将另一个then附加到Promise中的promiseChain,直到第一个then返回时才向前移动。附加的第一个then会立即前进,因为此时promiseChainPromise.resolve()

这也可以用reduce完成。

myFiles.reduce((acc, file) => acc.then(() => importFiles(file))), Promise.resolve())

答案 1 :(得分:1)

好像importFile没有返回承诺。这意味着承诺列表中充满了import re m = re.findall("=(.*?)=", "A =BC= D =EF=") 。您可以使用[undefined, undefined...]进行检查。调试“打印所有东西!”的第一步。将return语句放在 console.log()。至少这就是为什么“完成”在中间。您的csv检查排在最前面的原因是因为它们不是异步的,因此您的代码在控制处理异步部分的代码之前首先要进行所有操作。

答案 2 :(得分:0)

importFile必须是一个承诺,尝试一下:

const importFile = function(file){

    return new Promise(function(resolve, reject){

        isFileCSV(file).then((result) => {
            console.log(`01a File ${file} ends with csv? ${result}`);
            result = result.toLowerCase();

            if (result === 'false') {
                console.log(`01b ${result} = Not csv, log it and skip to next.`);
            } else if (result === 'true') {
                console.log(`01b ${result} = It is csv, go to next step`);
            }

            wasFileImported('file').then((result) => {
                console.log('03 checked import, result: ', result);

                switch(result) {
                    case 'false':
                        console.log('04a download file and log it');
                        break;
                    case 'true':
                        console.log('04b skip it and log the skip');
                        break;
                    default:
                        console.log('04c unknown error, log the skip');                         
                }

                return resolve(result);
            }) 

        });

    });     
}