Home > Software engineering >  How to stop a loop with setTimeout() method
How to stop a loop with setTimeout() method

Time:06-26

I have created a route in my REST API that produces a random food order for the user after they send a request with a bunch of parameters. I have a while loop that's loops through potential options and places them into a random Order array. The loop will run until there are as many items in the random order as numberOfHeads specified by the user. The issues is that sometimes it is impossible to create an order that has something for all mouths to feed and as a result the loop will run forever. As a backstop for this I would like to add two conditions to the while loop

  1. If the amount of items in the random order array matches the numberOfHeads specified by the user then the loop can stop.

  2. if its tried to do this for a number of seconds but finds itself looping infinitely, I want the loop to stop and simply serve up what is has managed to place in the randomOrder array. I have tried to implement this with the setTimeout() method but I cant seem to get it to change the keepCalling Boolean from true to false in order to stop the loop. I am also not sure if I can feed two conditions into a while loop where if either condition becomes true the loop stops?

  // RANDOM ORDER FILTER/GENERATOR
router.get("/randomorder", async (req, res) => {

    //USERS CHOSEN CATEGORIES SPH & NOP SENT THROUGH THE REQUEST
    const restCats = await req.body.restcategories
    const menueCats = await req.body.menuecats
    var totalSpend = await req.body.totalspend
    const numberOfHeads = await req.body.numberofheads
    const spendPerHead = totalSpend / numberOfHeads

    console.log(spendPerHead)


    let restOptions = await Restaurant.aggregate(
        [{
            $match: {
                categories: {
                    $in: restCats
                }
            }
        }]
    )


    let randomRestOption = restOptions[Math.floor(Math.random() * restOptions.length)];
    //RESULT OF ALL MENUE ITEMS MATCHING USER CATEGORIES
    let menueOptions = []

    //FULL RESULT OF BOTH RESTURANTS MATCHING USERS CHOSEN CATEGORIES AND MENUE ITEMS OF THOSE RESTURANTS MATCHING USERS CATEGORIES    


    // LOOPS THROUGH ALL RESTURANT OPTIONS MENUES AND OUTPUTS MENUE ITEMS MATCHING THE USERS CHOSEN CATEGORIES

    randomRestOption.menue.filter(function checkoptions(option) {
        for (let x = 0; x < option.categories.length; x  ) {
            // console.log(option)
            if (option.categories[x] === menueCats[0] || option.categories[x] === menueCats[1] || option.categories[x] === menueCats[2] || option.categories[x] === menueCats[3] || option.categories[x] === menueCats[4] || option.categories[x] === menueCats[5] || option.categories[x] === menueCats[6]) {
                // FILTERS RESULTS BASED ON TOTAL SPEND PER HEAD CHOSEN BY USER
                if (option.price <= spendPerHead) {
                    menueOptions.push(option)
                } else if (spendPerHead === undefined) {
                    menueOptions.push(option)

                }


            }
        }

    })

    var keepCalling = true

    const myTimeout = setTimeout(reAssign, 3000)



    function reAssign() {

        keepCalling = false
    }

    myTimeout

    let randomOrder = []

    console.log(keepCalling)

    while (randomOrder.length < numberOfHeads || keepCalling === true) {
        // console.log(keepCalling)
        let randomMenueOption = menueOptions[Math.floor(Math.random() * menueOptions.length)];

        // console.log(randomMenueOption)

        function checkDuplicates() {
            let duplicate = ""
            let itemName = randomMenueOption.name
            // console.log(itemName)
            for (let i = 0; i < randomOrder.length; i  ) {

                if (itemName === randomOrder[i].name) {
                    duplicate = "duplicate"

                }
                // console.log("loop running")
            }
            // console.log(randomOrder)
            return duplicate
        }

        let checkduplicate = checkDuplicates()


        if (checkduplicate === "duplicate") {
            // console.log("Found Duplicate")

        } else {
            randomOrder.push(randomMenueOption)
        }
        randomOrder.length;
        // console.log(randomMenueOption)
    }


    // console.log(spendPerHead)
    try {
        res.status(201).send({
            randomOrder


        })
    } catch (err) {
        console.log(err)
    }


})  

CodePudding user response:

setTimeout is an asynchronous that means that it will be executed by the event loop when the call stack is empty.

So in your use case it will never will execute because the loop will occupy the call stack.

If you want to get the same effect, you can use the Date object to capture the current time, and in each iteration in the check if it passed the timeTocancel.

let keepCalling = true;
const startingTime = Date.now();
const timeTocancel = 3000;

while (keepCalling) {
  const currentTime = Date.now();
  if (currentTime - startingTime >= timeTocancel ) break;
  console.log("do things");
}
  • Related