Javascript 如何在NodeJs中使一定数量的函数在循环中并行运行?

Javascript 如何在NodeJs中使一定数量的函数在循环中并行运行?,javascript,node.js,Javascript,Node.js,我正在寻找一种方法,在一个循环中同时运行3个相同的函数,并等待它完成,然后继续运行另外3个相同的函数。我认为它涉及一个循环,promise API。但我的解决办法是失败。如果你能告诉我我做错了什么以及如何修复它,那就太好了 以下是我迄今为止所做的工作: 我有一个下载功能(调用downloadFile),一个保留功能(调用runAfter)和一个多下载功能(调用downloadList)。它们看起来像这样: const https = require('https') const fs = re

我正在寻找一种方法,在一个循环中同时运行3个相同的函数,并等待它完成,然后继续运行另外3个相同的函数。我认为它涉及一个循环,promise API。但我的解决办法是失败。如果你能告诉我我做错了什么以及如何修复它,那就太好了

以下是我迄今为止所做的工作:


我有一个下载功能(调用
downloadFile
),一个保留功能(调用
runAfter
)和一个多下载功能(调用
downloadList
)。它们看起来像这样:

const https = require('https')
const fs = require('fs')
const { join } = require('path')
const chalk = require('chalk') // NPM
const mime = require('./MIME') // A small module read Json and turn it to object. It returns a file extension string.

exports.downloadFile = url => new Promise((resolve, reject) => {
    const req = https.request(url, res => {
        console.log('Accessing:', chalk.greenBright(url))
        console.log(res.statusCode, res.statusMessage)
        // console.log(res.headers)

        const ext = mime(res)
        const name = url
            .replace(/\?.+/i, '')
            .match(/[\ \w\.-]+$/i)[0]
            .substring(0, 250)
            .replace(`.${ext}`, '')
        const file = `${name}.${ext}`
        const stream = fs.createWriteStream(join('_DLs', file))

        res.pipe(stream)
        res.on('error', reject)

        stream
            .on('open', () => console.log(
                chalk.bold.cyan('Download:'),
                file
            ))
            .on('error', reject)
            .on('close', () => {
                console.log(chalk.bold.cyan('Completed:'), file)
                resolve(true)
            })
    })
    req.on('error', reject)
    req.end()
})

exports.runAfter = (ms, url) => new Promise((resolve, reject) => {
    setTimeout(() => {
        this.downloadFile(url)
            .then(resolve)
            .catch(reject)
    }, ms);
})

/* The list param is Array<String> only */
exports.downloadList = async (list, options) => {
    const opt = Object.assign({
        thread: 3,
        delayRange: {
            min: 100,
            max: 1000
        }
    }, options)

    // PROBLEM
    const multiThread = async (pos, run) => {
        const threads = []
        for (let t = pos; t < opt.thread + t; t++) threads.push(run(t))
        return await Promise.all(threads)
    }

    const inQueue = async run => {
        for (let i = 0; i < list.length; i += opt.thread)
            if (opt.thread > 1) await multiThread(i, run)
            else await run(i)
    }

    const delay = range => Math.floor(
        Math.random() * (new Date()).getHours() *
        (range.max - range.min) + range.min
    )

    inQueue(i => this.runAfter(delay(opt.delayRange), list[i]))
}
const multiThread = async (pos, run) => {
  const threads = [];
  for (let t = 0; t < opt.thread && pos+t < list.length; t++)  {
    threads.push(run(pos + t));
  }
  return await Promise.all(threads);
};
显然,
downloadList
multi-thread
)的子函数是一个原因,但我无法读取这些数字(似乎是RAM的物理地址之类的),所以我不知道如何修复它。我不是专业工程师,如果你能给我一个好的解释,我将不胜感激

补充资料:

  • NodeJs版本:12.13.1
  • 本地主机:Aspire SW3-013>1.9GB(规格为2GB)/Intel Atom CPU Z3735F
  • 通过WiFi连接到互联网(Realtek drive)
  • 操作系统:Windows 10(无其他选择)
如果您可能会问:

  • 为什么要包装
    下载文件的承诺?对于进一步的应用,我可以把它放在其他应用程序中,一次只需要下载一次
  • runAfter
    重要吗?也许没有,只是给自己一点挑战。但如果服务器需要延迟下载时间,它可能会很有用
  • 家庭作业还是生意?没有,只有爱好。我计划构建一个应用程序,从Unsplash的API获取和下载图像。所以我更喜欢一个好的解释我做错了什么以及如何修复它,而不是一个简单的代码

您的for循环在
多线程中永不会结束,因为您的继续条件是
t
。如果
opt.thread
不为零,则将始终为
true
。这里有一个无限循环,这就是崩溃的原因

我怀疑你想做这样的事:

const https = require('https')
const fs = require('fs')
const { join } = require('path')
const chalk = require('chalk') // NPM
const mime = require('./MIME') // A small module read Json and turn it to object. It returns a file extension string.

exports.downloadFile = url => new Promise((resolve, reject) => {
    const req = https.request(url, res => {
        console.log('Accessing:', chalk.greenBright(url))
        console.log(res.statusCode, res.statusMessage)
        // console.log(res.headers)

        const ext = mime(res)
        const name = url
            .replace(/\?.+/i, '')
            .match(/[\ \w\.-]+$/i)[0]
            .substring(0, 250)
            .replace(`.${ext}`, '')
        const file = `${name}.${ext}`
        const stream = fs.createWriteStream(join('_DLs', file))

        res.pipe(stream)
        res.on('error', reject)

        stream
            .on('open', () => console.log(
                chalk.bold.cyan('Download:'),
                file
            ))
            .on('error', reject)
            .on('close', () => {
                console.log(chalk.bold.cyan('Completed:'), file)
                resolve(true)
            })
    })
    req.on('error', reject)
    req.end()
})

exports.runAfter = (ms, url) => new Promise((resolve, reject) => {
    setTimeout(() => {
        this.downloadFile(url)
            .then(resolve)
            .catch(reject)
    }, ms);
})

/* The list param is Array<String> only */
exports.downloadList = async (list, options) => {
    const opt = Object.assign({
        thread: 3,
        delayRange: {
            min: 100,
            max: 1000
        }
    }, options)

    // PROBLEM
    const multiThread = async (pos, run) => {
        const threads = []
        for (let t = pos; t < opt.thread + t; t++) threads.push(run(t))
        return await Promise.all(threads)
    }

    const inQueue = async run => {
        for (let i = 0; i < list.length; i += opt.thread)
            if (opt.thread > 1) await multiThread(i, run)
            else await run(i)
    }

    const delay = range => Math.floor(
        Math.random() * (new Date()).getHours() *
        (range.max - range.min) + range.min
    )

    inQueue(i => this.runAfter(delay(opt.delayRange), list[i]))
}
const multiThread = async (pos, run) => {
  const threads = [];
  for (let t = 0; t < opt.thread && pos+t < list.length; t++)  {
    threads.push(run(pos + t));
  }
  return await Promise.all(threads);
};

这一行是(让t=pos;t
,这是打字错误吗?在你的例子中,
t
总是小于
opt.thread+t
,这意味着一个无限循环。这是否回答了你的问题:我在循环中犯这样的错误太愚蠢了。在这里,我认为我犯了一些可怕的错误,使用了太多的承诺或其他东西。非常感谢你的良好和明确的解释。