0

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()

I'm going to execute mainTasks as sync and subTasks as async At the end, I try catch the point when the mainTasks are all finished as well subTasks. Seems I got the point But I met the unexpected result.

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

Where is mainTask4 -> subTask1 and 2??

1 Answer 1

2

With your

for (subTask of subTasks) {

You forgot to declare the subTask variable, so it's implicitly global - it doesn't have block scope. It gets reassigned on every iteration and on every maintask. So, after the asynchronous await inside the for:

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

By the time any of the awaits resolve, the subTask variable will hold the value assigned to it during the most recently initialized subtask (rather than the variable assigned to it during the current subtask).

Change to:

for (const subTask of subTasks) {

and it'll work as expected.

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()

You could also consider using strict mode and/or a linter, to catch these errors earlier:

'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()

Error: Unhandled promise rejection: ReferenceError: subTask is not defined

Sign up to request clarification or add additional context in comments.

1 Comment

thats why you "use strict";

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.