简体   繁体   中英

How to stop a loop with setTimeout() method

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 loops through potential options and places them into the randomOrder array. The loop will run until there are as many items in the random order as numberOfHeads specified by the user. The issue 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 it 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 it has managed to place in the randomOrder array. I have tried to implement this with the setTimeout() method but I can't 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)
    }


})  

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");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM