首页 > 解决方案 > 在同步函数中正确执行异步函数

问题描述

const mainTasks = ['mainTask1', 'mainTask2', 'mainTask3', 'mainTask4']
const subTasks = ['subTask1', 'subTask2', 'subTask3']
const defaultTimeout = 1000

// SubTasks should be run as async
// Tasks should be run as sync

const subTaskHandler = () => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve();
        }, defaultTimeout * 2);
    })
}

const main = async () => {
    await Promise.all(
        mainTasks.map((mainTask, index) => {
            return new Promise(resolve => {
                setTimeout(async () => {
                    for (subTask of subTasks) {
                        await subTaskHandler(defaultTimeout)
                        console.log(`${mainTask} -> ${subTask}: Completed`)
                    }
                    resolve()
                }, defaultTimeout + index * 1000)
            })

        })
    )
    console.log('done')
}

main()

我将mainTasks作为 sync 和subTasks作为 async 执行 最后,我尝试抓住mainTasks 以及subTasks都完成的。看来我明白了但我遇到了意想不到的结果。

mainTask1 -> subTask1: Completed
mainTask2 -> subTask1: Completed
mainTask3 -> subTask2: Completed
mainTask1 -> subTask2: Completed
mainTask4 -> subTask3: Completed
mainTask2 -> subTask2: Completed
mainTask3 -> subTask3: Completed
mainTask1 -> subTask3: Completed
mainTask4 -> subTask3: Completed
mainTask2 -> subTask3: Completed
mainTask3 -> subTask3: Completed
mainTask4 -> subTask3: Completed
done

mainTask4 -> subTask1和 2在哪里?

标签: node.jsasynchronouspromisesynchronization

解决方案


跟你的

for (subTask of subTasks) {

您忘记声明subTask变量,因此它是隐式全局的 - 它没有块范围。它在每次迭代每个主要任务上都会重新分配。所以,在异步await之后for

                for (subTask of subTasks) {
                    await subTaskHandler(defaultTimeout)
                    console.log(`${mainTask} -> ${subTask}: Completed`)
                }

到任何awaits 解决时,该subTask变量将保存在最近初始化的子任务期间分配给它的值(而不是在当前子任务期间分配给它的变量)。

改成:

for (const subTask of subTasks) {

它会按预期工作。

const mainTasks = ['mainTask1', 'mainTask2', 'mainTask3', 'mainTask4']
const subTasks = ['subTask1', 'subTask2', 'subTask3']
const defaultTimeout = 1000

// SubTasks should be run as async
// Tasks should be run as sync

const subTaskHandler = () => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve();
        }, defaultTimeout * 2);
    })
}

const main = async () => {
    await Promise.all(
        mainTasks.map((mainTask, index) => {
            return new Promise(resolve => {
                setTimeout(async () => {
                    for (const subTask of subTasks) {
                        await subTaskHandler(defaultTimeout)
                        console.log(`${mainTask} -> ${subTask}: Completed`)
                    }
                    resolve()
                }, defaultTimeout + index * 1000)
            })

        })
    )
    console.log('done')
}

main()

您还可以考虑使用严格模式和/或 linter 来更早地捕获这些错误:

'use strict';

const mainTasks = ['mainTask1', 'mainTask2', 'mainTask3', 'mainTask4']
const subTasks = ['subTask1', 'subTask2', 'subTask3']
const defaultTimeout = 1000

// SubTasks should be run as async
// Tasks should be run as sync

const subTaskHandler = () => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve();
        }, defaultTimeout * 2);
    })
}

const main = async () => {
    await Promise.all(
        mainTasks.map((mainTask, index) => {
            return new Promise(resolve => {
                setTimeout(async () => {
                    for (subTask of subTasks) {
                        await subTaskHandler(defaultTimeout)
                        console.log(`${mainTask} -> ${subTask}: Completed`)
                    }
                    resolve()
                }, defaultTimeout + index * 1000)
            })

        })
    )
    console.log('done')
}

main()

错误:未处理的承诺拒绝:ReferenceError:未定义子任务


推荐阅读