使用 async await + setTimeout 分割 while 循环

由于JavaScript单线程的特性,在执行CPU密集型任务时(如大数组排序)会阻塞网页的渲染,解决办法一般是使用setTimeout函数对任务进行分割,或者把这类任务交由 web worker 处理。今天遇到一个对大数组排序的问题,需要使用任务分割来避免阻塞,在这里记录下我的实现方法。在实现时我将 while 语句进行了分割,避免出现大循环体语句一直进行计算,主要代码如下:

    //while 控制语句进行分割
    // expression 相当于 while 的条件判断
    // statement 相当于 while 循环体语句
    async function while_async(expression, statement){
        while(expression()){
            await while_seg(expression, statement);
        }
    }

    let while_seg = (expression, statement) => new Promise((resolve, reject) => {
        setTimeout(()=>{
            let i = 0;
            let while_size = 50000;
            while(expression()){
                i++;
                statement();
                // 如果 while 内循环次数大于 while_size ,则进入事件循环
                if(i>while_size)break;
            }
            resolve();
        }, 0);
    });

应用在大数组排序上,效果对比可以在这里查看:https://codepen.io/liuyaqi/pen/dmZdPe

height="351" width="650" scrolling="no" title="while_seg" src="//codepen.io/liuyaqi/embed/dmZdPe/?height=351&theme-id=0&default-tab=result&embed-version=2" allowfullscreen="true">See the Pen while_seg by liuyaqi (@liuyaqi) on CodePen.

全部代码如下:

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
    <style>
        div{
            width: 100px;
            height: 100px;
            margin-left: 0;
            background-color: aqua;
            animation: animation 3s infinite ;
        }
        div:hover{
            background-color: white;
        }
        @keyframes animation {
            0% {
                margin-left: 0;
            }
            50% {
                margin-left: 500px;
            }
            100% {
                margin-left: 0;
            }
        }
    style>
head>
<body>
    <div>div>
    <button id="sort">sortbutton>
    <button id="s_sort">setTimeout+sortbutton>
body>
<script>
    let data = [];
    let size = 2000000;

    for(let i=0; iMath.floor(Math.random()*size));
    }
    console.log(data);

    document.querySelector("#sort").onclick = ()=>{
        data.sort((a, b) => a-b);
        console.log("排序结果", data);
        alert("done");
    }
    document.querySelector("#s_sort").onclick = async ()=>{
        let res = await mergeSort_async(data);
        console.log("排序结果", res);
        alert("done");
    }

    // 归并排序算法
    async function mergeSort_async(array){
        var length = array.length;
        // 如果数组长度小于10000,直接排序
        if(length<10000){
            return array.sort((a, b) => a-b);
        }

        var mid = Math.floor(length / 2),
            left = array.slice(0, mid),
            right = array.slice(mid, length);

        return await merge_async(await mergeSort_async(left), await mergeSort_async(right));
    }

    async function merge_async(left, right){
        var result = [],
            il = 0,
            ir = 0;
        var args = {il, ir, result, left, right};

         await while_async(()=>(il < left.length && ir < right.length), ()=>{
            if(left[il] < right[ir]){
                result.push(left[il++]);
            }else{
                result.push(right[ir++]);
            }
        });

        await while_async(()=>(il < left.length), ()=>{
            result.push(left[il++]);
        });

        await while_async(()=>(ir < right.length), ()=>{
            result.push(right[ir++]);
        });

        return result;
    }

    // 将 while 控制语句进行分割
    // expression 相当于 while 的条件判断
    // statement 相当于 while 循环体语句
    async function while_async(expression, statement){
        while(expression()){
            await while_seg(expression, statement);
        }
    }

    let while_seg = (expression, statement) => new Promise((resolve, reject) => {
        setTimeout(()=>{
            let i = 0;
            let while_size = 50000;
            while(expression()){
                i++;
                statement();
                // 如果 while 内循环次数大于 while_size ,则进入事件循环
                if(i>while_size)break;
            }
            resolve();
        }, 0);
    });
script>
html>

你可能感兴趣的:(js)