简体   繁体   English

如何使用 setTimeout() 方法停止循环

[英]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.我在我的 REST API 中创建了一个路由,在用户发送带有一堆参数的请求后,它会为用户生成一个随机的食物订单。 I have a while loop that loops through potential options and places them into the randomOrder array.我有一个 while 循环,它遍历潜在的选项并将它们放入randomOrder数组。 The loop will run until there are as many items in the random order as numberOfHeads specified by the user.循环将一直运行,直到随机顺序中的项目数量与用户指定的numberOfHeads一样多。 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作为对此的支持,我想在 while 循环中添加两个条件

  1. If the amount of items in the random order array matches the numberOfHeads specified by the user then the loop can stop.如果随机顺序数组中的项目数量与用户指定的numberOfHeads匹配,则循环可以停止。

  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.如果它尝试这样做几秒钟但发现自己无限循环,我希望循环停止并简单地提供它已设法放置在randomOrder数组中的内容。 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.我试图用setTimeout()方法来实现它,但我似乎无法让它将keepCalling Boolean 从true更改为false以停止循环。 I am also not sure if I can feed two conditions into a while loop where if either condition becomes true the loop stops?我也不确定是否可以将两个条件输入到 while 循环中,如果任一条件为真,则循环停止?

// 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 . setTimeoutasynchronous的,这意味着它将call stack为空时由event loop执行。

So in your use case it will never will execute because the loop will occupy the call stack .因此,在您的用例中,它将永远不会执行,因为循环将占用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 .如果你想得到同样的效果,你可以使用Date对象来捕获当前时间,并在每次迭代中检查它是否通过了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");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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