Debugging: ESLint Warning “Function declared in a loop contains unsafe references to variable(s)…no-loop-func”

空扰寡人 提交于 2020-06-28 04:49:27

问题


Building a Sort-Visualizer in React using the Create-React-App [https://roy-05.github.io/sort-visualizer/ ]

I'm animating each iteration of the loop using setTimeouts. On dev console I get the following warning:

Line 156:32: Function declared in a loop contains unsafe references to variable(s) 'minimum', 'minimum', 'minimum', 'minimum' no-loop-func

Here's the code-snippet:

for(let i=0; i<arr.length-1; i++){
            let minimum = i; //Declare minimum here
            setTimeout(()=>{
                for(let j = i+1; j<arr.length; j++){
                    setTimeout(()=>{
                        //Getting a warning for these references:
                        array_bar[j].style.backgroundColor = 'red';
                        array_bar[minimum].style.backgroundColor = 'blue';
                        setTimeout(()=>{
                            if(arr[j] < arr[minimum]){
                            array_bar[minimum].style.backgroundColor = 'lightblue';
                            minimum = j; 
                            }  
                            else{
                                array_bar[j].style.backgroundColor = 'lightblue';
                            }  
                        }, 4);
                    }, (j-1)*4);    
                }

Going through ESLint Docs, I believe the issue might be that i'm modifying the value inside the setTimeout but the variable is declared outside its scope.

I'm not sure how to fix that warning, any help will be appreciated!

Note: Here's the entire function if you need it -

selectionSort(){
        const arr = this.state.array,
            array_bar = document.getElementsByClassName("array-elem");

        this.setState({startedSelectionSort: true});

        for(let i=0; i<arr.length-1; i++){
            let minimum = i; //Declare minimum here
            setTimeout(()=>{
                for(let j = i+1; j<arr.length; j++){
                    setTimeout(()=>{
                        //Getting a warning for these references:
                        array_bar[j].style.backgroundColor = 'red';
                        array_bar[minimum].style.backgroundColor = 'blue';
                        setTimeout(()=>{
                            if(arr[j] < arr[minimum]){
                            array_bar[minimum].style.backgroundColor = 'lightblue';
                            minimum = j; 
                            }  
                            else{
                                array_bar[j].style.backgroundColor = 'lightblue';
                            }  
                        }, 4);
                    }, (j-1)*4);    
                }
                setTimeout(()=>{
                    let temp = arr[i],
                    arr1_height = arr[minimum],
                    arr2_height = arr[i];

                    arr[i] = arr[minimum];
                    arr[minimum] = temp;

                    array_bar[i].style.height = `${arr1_height}px`;
                    array_bar[minimum].style.height = `${arr2_height}px`;

                    array_bar[i].style.backgroundColor = "green";
                    if(i !== minimum){
                        array_bar[minimum].style.backgroundColor = 'lightblue';
                    }
                }, 400);


                if(i === arr.length-2){
                    setTimeout(()=>{
                        array_bar[i+1].style.backgroundColor = "green";
                    },800);
                }

            }, i*400);
        }

        setTimeout(()=>{
            this.setState({sorted: true})
        }, arr.length*400+1750);

    }

回答1:


I also encountered same warning. In my case, I declared variable outside the iteration, but modified variable inside forEach method.

Something like:

// some code above
let validInputs = true;

someInputs.forEach( input => {
  validInputs = input.value && validInputs;
})

After I did some reserch, I found in this post, JSHint error : Functions declared within loops referencing an outer scoped variable may lead to confusing semantics, mentioned that JSHint doesn't like how the anonymous function in there is being re-created over and over.

I changed forEach arrow function to for (let index i = 0; index < someInputs.length; index++), and the warning is gone.

Perhaps in your case, change setTimeout to traditional non-arrow function can remove the warning.




回答2:


You're correct that modifying the variable inside setTimeout is causing the issue. You can get around this by wrapping setTimeout inside a promise and waiting for it to resolve before modifying your variables. This is much cleaner using async/await:

for (let i = 0; i < arr.length - 1; i++) {
    let minimum = i;
    await new Promise(resolve => setTimeout(resolve, i * 400));
    for (let j = i + 1; j < arr.length; j++) {
        array_bar[j].style.backgroundColor = "red";
        array_bar[minimum].style.backgroundColor = "blue";

        await new Promise(resolve => setTimeout(resolve, (j - 1) * 400));
        if (arr[j] < arr[minimum]) {
            array_bar[minimum].style.backgroundColor = "lightblue";
            minimum = j;
        }
    }
}

With each loop, you're creating a promise that resolves once the timeout is expired. Using await will pause execution of your function until the promise resolves. Then, you can modify variables like minimum because they are no longer within the scope of the callback function you were originally passing into setTimeout.



来源:https://stackoverflow.com/questions/58816244/debugging-eslint-warning-function-declared-in-a-loop-contains-unsafe-reference

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!