Node.js异步功能是否可以并行执行?

时间:2020-05-08 12:18:03

标签: node.js asynchronous parallel-processing async-await

以下代码用于:

  1. 转换一些视频并将其存储在转换后的文件夹中。
  2. CONCATENATE转换后的视频。
  3. 清除转换后的文件夹。

当前,在执行代码时,它在转换时会串联在一起,并最终引发错误。我需要按其各自的顺序优先执行每个功能。

const glob = require('glob');
const exec = require('child_process').exec;
const { unlink } = require("fs").promises;

function start(index) {


  const path = `./files/${index}`;
  const ConvertedVideos=path+"/converted/*.mp4";
  const videos = glob.sync(path+"/videos/*.mp4");
  const outputnoaudio = path+"/outputnoaudio.mp4";




  //THIS IS THE ORDER OF EXECUTION

  await convertVideos()
  await withFfmpegConcatVideo()
  await clearConverted()



  //HERE THE DEFINITION OF EACH FUNCTION

  async function convertVideos() {
    return new Promise((resolve) => {

      console.log('>>>Starting conversion!!!');
      const promises = videos.map(
        (video, index) => {
          var command = `ffmpeg -i ${video} -c:v libx264 -vf scale=1920:1080 -r 60 -c:a aac -ar 48000 -b:a 160k -strict experimental -f mp4 ./converted/${index}.mp4`;

          return new Promise((resolve) => {
            exec(command, (error, stdout, stderr) => {
              if (error) {
                console.warn(error);
              }
              resolve(stdout ? stdout : stderr);
              console.log('Converted video', index);
            });
          });
        }
      )
      Promise.all(promises);
      resolve();
    })
  }

  async function withFfmpegConcatVideo() {
    return new Promise((resolve) => {

      console.log('Starting concatenation...');

      var converted = glob.sync(ConvertedVideos);

      console.log('There is ', converted.length, 'converted videos');

      if (converted.length > 0) {

        (async () =>
          await concat({
            output: outputnoaudio,
            videos: converted,
            transition: {
              name: 'fade',
              duration: 200
            }
          }))()
      }
      resolve(console.log('Conversion finished'));
    })
  }


  async function clearConverted() {

    return new Promise((resolve) => {

      const converted =
        glob.sync(ConvertedVideos)

      if (converted.length === 0)
        return Promise.resolve([])

      const promises =
        converted.map(v => unlink(v).then(_ => {
          v
        }))

      Promise.all(promises).then('Clean done.')
      resolve();
    })
  }
}

start(1);

我想保持干净且可重复使用的代码。 你能帮我吗?

3 个答案:

答案 0 :(得分:1)

您的start函数看起来不正确,因为您缺少async运算符。

为清楚起见,建议将其更像C文件一样对待,并在其中调用async function main() {}await的三个函数。

在您的convertVideos函数中,您正在呼叫Promise.all(),但是您没有等待它。请注意,Promise.all()实际上也返回了一个Promise,您必须等待它,但是为了让您等待它,周围的函数还必须具有async关键字。我在clearConverted函数中看到了同样的问题。

尝试等待您的Promise.all通话,看看是否可以解决您的问题。

实际上,您的convertVideos函数似乎将所有内容包装在Promise中,我认为您不需要。试试这个:

function convertVideos() {
    console.log('>>>Starting conversion!!!');
    const promises = videos.map(
        (video, index) => {
            var command = `ffmpeg -i ${video} -c:v libx264 -vf scale=1920:1080 -r 60 -c:a aac -ar 48000 -b:a 160k -strict experimental -f mp4 ./converted/${index}.mp4`;

            return new Promise((resolve) => {
                exec(command, (error, stdout, stderr) => {
                    if (error) {
                       console.warn(error);
                    } 
                resolve(stdout ? stdout : stderr);
                console.log('Converted video', index);
            });
        });
      });


    // Notice that you can return this promise from Promise.all.
    // The caller can then await this promise that will let you know when
    // all the videos are converted.
    return Promise.all(promises);
}

答案 1 :(得分:1)

withFfmpegConcatVideo().then(() => clearConverted());

应该做到这一点

答案 2 :(得分:0)

由于您的评论,我刚刚修复了代码,并找到了解决方案。


const glob = require('glob');
const concat = require('ffmpeg-concat');
const {
  unlink
} =
require("fs").promises;
const exec = require("child_process").exec;

async function start(index){



  const path = `./files/${index}`;
  const pathToConverted = `${path}/converted`;
  const videos = glob.sync(`${path}/[0-99]/videoKeywords/[0-99]/*output.mp4`);
  const output = `${path}/output.mp4`;
  const outputmuted = `${path}/outputmuted.mp4`;




   async function clearConverted() {

    await new Promise(async (resolve) => {
      console.log('Starting cleaning...');
      const converted = glob.sync(`${pathToConverted}/*.mp4`)

      if (converted.length === 0)
        return Promise.resolve([])

      const promises =
        converted.map(v => unlink(v).then(_ => {
          console.log("   File Deleted");
          v
        }))

      await Promise.all(promises).then(async () => await console.log('Clean done.'))

      resolve()
    })
  }




async function convertVideos() {
    await new Promise(async (resolve) => {

      console.log('>>>Starting conversion of', videos.length, 'files!!!');


      for (let i = 0; i < videos.length; i++) {

        let video = videos[i];

        var command = `ffmpeg -i ${video} -c:v libx264 -vf scale=1920:1080 -r 60 -c:a aac -ar 48000 -b:a 160k -strict experimental -f mp4 ${pathToConverted}/${i}.mp4`;

        await new Promise((resolve) => {
          exec(command, (error, stdout, stderr) => {
            if (error) {
              console.warn(error);
            }
            resolve(stdout ? stdout : stderr);
            console.log('  Converted video', i);
          });
        });
      }
      resolve();
    }).then(async () => await console.log('Conversion finished!!!'))
  }




 async function clearConverted() {

    await new Promise(async (resolve) => {
      console.log('Starting cleaning...');
      const converted = glob.sync(`${pathToConverted}/*.mp4`)

      if (converted.length === 0)
        return Promise.resolve([])

      const promises =
        converted.map(v => unlink(v).then(_ => {
          console.log("   File Deleted");
          v
        }))

      await Promise.all(promises).then(async () => await console.log('Clean done.'))

      resolve()
    })
  }
}
start(0);

请注意,function convertVideos()的此实现顺序执行异步转换,这意味着它将逐步转换一个文件。 在此功能的先前实现上,执行是并行执行的,如果您有多个内核,这对于转换几个视频来说是最佳选择。

如果您有任何代码建议可同时处理大量视频,请随时提供支持。