简体   繁体   English

如何在数组的每个项目上正确地使异步列表异步任务

[英]How to properly make synchrnous a list of asynchronous task on each item of an array

I need to perform several task in a synchronous way. 我需要以同步方式执行多个任务。 Extract some files from a folder and its subfolders into an array of items and then make a temp copy of all of them. 从文件夹及其子文件夹中提取一些文件到一组项目中,然后对其进行临时复制。 Those two task I managed to do them synchronously. 我成功地完成了这两个任务。

Then I need to perform 7 task on every of the item of the array, and I need to wait for the 7 task to be finished for one before passing to the next one. 然后,我需要在数组的每个项目上执行7个任务,并且我需要等待7个任务完成一项,然后再传递到下一个任务。

But every attempt I made ended by doing tasks in this order: Exemple for 3 files to process : 但是,我所做的每一次尝试都以以下顺序完成任务:例如,要处理3个文件:

1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 6 7 6 7 6 7. And I would like it to be : 1 2 3 4 5 6 7 1 2 3 4 5 6 7 1 2 3 4 5 6 7 The lasts two tasks are stacked up and only triggered when the 5 firsts tasks have ne made for every files. 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 6 7 6 7 6 7.我希望是:1 2 3 4 5 6 7 1 2 3 4 5 6 7 1 2 3 4 5 6 7最后两个任务堆叠在一起,只有在为每个文件都完成5个“最先”任务时才触发。

Here I how I start the script : 在这里,我如何启动脚本:

start();

async function start() {
    await listDirToProcess(); // This works
    await makeSafeCopy(); // This works as well
    for (var currentDCF of dirToProcess) {
        Perform the 7 tasks... 
    }
}

I tried with a callback hell(every thing in the callback of the previous task) I tried without the start() function I tried with more or less async/await keys words I also tried with an asyncForEach function I found in SO instead of the current for-of loop : 我尝试了一个回调地狱(上一个任务的回调中的所有事情)我尝试了没有start()函数的情况我尝试了或多或少的async / await关键字我也尝试了在SO中找到的asyncForEach函数而不是当前for-of循环:

async function asyncForEach(array, callback) {
    for (let index = 0; index < array.length; index++) {
        await callback(array[index], index, array);
    }
}

But none of them did the trick. 但是他们都没有成功。

I'm currently using a for(xx of yy) loop to go through the array. 我目前正在使用for(xx yy)循环来遍历数组。

Here is a summary of those tasks : 以下是这些任务的摘要:
Step 1 : Copy files to another folder, i'm doing this like that : 第1步:将文件复制到另一个文件夹,我正在这样做:

// Usage of the function 
await copyToSomeDir(stuff, (err) => {
    err == 0 ?
        log.info('\t\tCopy to xxx went well') :
        log.info('\t\tCopy to xxx ended with ' + err + " error ");
    });
// Definition of the function
function copyToSomeDir(item, cb) { // Notice i didn't put the async key word
    ...
    cb(i);
}

Step 2 : Wait for an external app to do a job on the Step 1 output folder 步骤2:等待外部应用程序在步骤1输出文件夹中完成工作

// Usage of the function 
await execExternJob();
// Definition of the function
function execExternJob() {
    log.info("Executing Talend job")
    child_process.execSync(cmd_to_exe, (error, stdout, stderr) => {
        log.info("job completed for the " + item.entity);
    })
}

Step 3 : Check the result of the previous extern job : 步骤3:检查上一个外部作业的结果:

// Usage of the function 
await checkSuccessfulJob(xxx, (list) => {
    ...
    });
// Definition of the function
function checkSuccessfulJob(xxx, cb) {
    ...
    cb(list);
}

Step 4: Replace some files by others 步骤4:将其他档案替换为其他档案

// Usage of the function 
await OverwriteSucessFile(currentDCF.talendResult.success);
// Definition of the function
function OverwriteSucessFile(list) {
    ...
};

!!! And here is the step that break it all. 这是打破一切的步骤。 !!! Step 5 - 6 - 7: If not everything went well during the external job, do stuff Else Zip a folder and upload it to a web service(a CMS actually). 步骤5-6-7:如果在外部工作期间一切都不顺利,则在Else Zip文件夹中做一些事,然后将其上传到Web服务(实际上是CMS)。

if (fault) {
   fault.forEach((faultyFile) => {
       ... // Not important
   })
} else {
//Usage of the function 
    await prepareZipFolder(xxx, yyy, (path) => { // Step 5
        getUrlFromFile(AlfrescoUrl, (url) => { // Step 6
            uploadToCMS(url, path (ok) => { // Step 7
                        log...
                    })
                });
            });
}

Here is the definition of what I think is the problematic function : 这是我认为是有问题的功能的定义:

async function prepareZipFolder(zipFileName, rootZipFolder, callback) {
    var zipFile = fs.createWriteStream(path.join(rootZipFolder, zipFileName) + ".zip");
    // >>>>>>>>>>>   Here is where it pass to the next itteration instead of waiting the end of the archiving. I think !     <<<<<<<<<<<
    var archive = archiver('zip', {
        zlib: { level: 9 } // Sets the compression level.
    });
    zipFile.on('close', () => {
        callback(path.join(rootZipFolder, zipFileName) + ".zip")
    })
    zipFile.on('open', (fd) => {
        archive.on('error', function (err) { log.info(err) });
        archive.pipe(zipFile);
        archive.glob("**", { cwd: path.join(rootZipFolder, zipFileName) }, { prefix: zipFileName });
        archive.finalize();
    })
}

The problem is, when the .zip fil is created, the loop pass to the next item instead of waiting for the archiving to be over. 问题是,创建.zip fil时,循环将传递到下一个项目,而不是等待归档结束。

Sorry for the long question, can someone help ? 很抱歉,这个问题很长,有人可以帮忙吗?

If I understand correctly, you constantly mix promisified functions with callback functions (also some strange things happen like child_process.execSync(cmd_to_exe, (error, stdout, stderr) => {...Sync functions do not use callbacks, but this can be a typo). 如果我理解正确,您会不断将promisified函数与回调函数混合使用(还会发生一些奇怪的事情,例如child_process.execSync(cmd_to_exe, (error, stdout, stderr) => {...Sync函数不使用回调,但是可以是一个错字)。

You need to stick with one approach. 您需要坚持一种方法。 If some API does not provide functions that return Promise, these functions will not become Promise-compatible if you just add await before them. 如果某些API不提供返回Promise的功能,则仅在它们之前添加await不会与Promise兼容。 You need to find another API or to promisify your wrapper functions by yourself. 您需要自己寻找另一个API或实现包装函数的功能。

For example, your step 2: 例如,您的步骤2:

await execExternJob();

function execExternJob() {
    log.info("Executing Talend job")
    child_process.execSync(cmd_to_exe, (error, stdout, stderr) => {
        log.info("job completed for the " + item.entity);
    })
}

can be rewritten as: 可以重写为:

await execExternJob();

function execExternJob() {
  log.info("Executing Talend job");

  return new Promise((resolve, reject) => {
    child_process.exec(cmd_to_exe, (error, stdout, stderr) => {
      if (error) {
        reject(error);
      } else {
        log.info("job completed for the " + item.entity);
        resolve();
      }
    });
  });
}

And so on. 等等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM