await vs then 脑回路记录

1,164 阅读4分钟

1 前因后果

今天又是一天努力工作(水群)的一天,突然看到群友在说某依框架垃圾,理由是没有封装请求,还要在代码里写.then

emmmmm.....

在我印象中是有几个后台管理是请求封装成return await xxxx这样的,忘了是ant design pro 还是jeecgboot了,也可能都不是,当初没觉得有啥不好,觉得这样代码执行顺序可控啊。

2 思前想后

不过今天的我已经不是昨天的我了

我当场提出质问:为哈?.then有什么不好

群友:大家不都是async await?

算了上图聊天截图吧!!!

image.png

image.png

深度不自信性格的我陷入了沉思:同步写法,异步执行

今年有幸耐住性子把前端红宝石书看了一些,刚好有看了await/async 和 Promise,但是记忆有些模糊了。

记得await是会导致同步代码的后续会暂停是肯定的,但是await如果后面还是异步请求呢?很像这个说法,给我整迷糊了一下。脑子里的代码逻辑当时如下:

const a = await fetch() // 发出请求
const b = await fetch() // 发出请求,等待a赋值好,b再赋值

聊天记录里能够看出我的大脑告诉我是20s,不自信的我被引导成await完还是5s。

本着实践出真知(先检查自己的想法是否正确,再有底气)的敲起了demo

3 实践

demo1 await

async function getData(num: number) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(num)
        }, 2000)
    })
}


const App = () => {
    const [value1, setValue1] = useState(0)
    const [value2, setValue2] = useState(0)
    const [value3, setValue3] = useState(0)
    const [value4, setValue4] = useState(0)

    const fetchData = useCallback(async () => {
        try {
            const beginTime = Date.now()
            console.log('beginTime', beginTime)
            const data1 = await getData(1)
            const data2 = await getData(2)
            const data3 = await getData(3)
            const data4 = await getData(4)
            setValue1(data1);
            setValue2(data2);
            setValue3(data3);
            setValue4(data4);
            const endTime = Date.now()
            console.log('endTIme:', endTime)
            console.log(endTime - beginTime)
        } catch (error) {
            console.error('Error fetching data:', error);
        }
    }, []);

    useEffect(() => {
        fetchData();
    }, [fetchData]);

    return (
        <div>
            {value1}
            {value2}
            {value3}
            {value4}
        </div>
    );
};

c7ff11f8c79a0559e61cbd74a5cdd5f.png

demo2 then

async function getData(num: number) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(num)
        }, 2000)
    })
}


const App = () => {
    const [value1, setValue1] = useState(0)
    const [value2, setValue2] = useState(0)
    const [value3, setValue3] = useState(0)
    const [value4, setValue4] = useState(0)

    const count = useRef(0)
    const beginTime = useRef()
    const endTime = useRef()
    const compute = useCallback(() => {
        count.current += 1
        if (count.current === 4) {
            endTime.current = Date.now()
            console.log('endTIme:', endTime)
            console.log(endTime.current - beginTime.current)
        }
    }, [])

    useEffect(() => {
        beginTime.current = Date.now()
        console.log('beginTime', beginTime)
        getData(1).then(data => {
            setValue1(data)
            compute()
        })
        getData(2).then(data => {
            setValue2(data)
            compute()
        })
        getData(3).then(data => {
            setValue3(data)
            compute()
        })
        getData(4).then(data => {
            setValue4(data)
            compute()
        })
    }, []);

    return (
        <div>
            {value1}
            {value2}
            {value3}
            {value4}
        </div>
    );
};

2a2cf03bb3634c3f4cbf25c39408642.png

结论

  • 在一个只有表格的页面的情况下 await和then没差别,就一个请求
  • 在多个请求的情况下,渲染独立多个地方的时候,明显then更好

当然也是可以优化的,配合Promise

try {
    const results = await Promise.all([
        getData(1),
        getData(2),
        getData(3),
        getData(4)
    ]);
    setValue1(results[0]);
    setValue2(results[1]);
    setValue3(results[2]);
    setValue4(results[3]);
} catch (error) {
    console.error('Error fetching data:', error);
}

4 继续工作(摸x)

也不知道怎么的我就开启了回忆,(大脑的结构真是复杂),想到了回调地狱....

曾几何时我也是个很菜很菜很菜的菜逼,当时写then的时候是这么写的,所以曾经一味的觉得await永远的神,这么封装很牛逼。

getData(1).then(data => {
    setValue1(data)
    compute()
    getData(2).then(data => {
        setValue2(data)
        compute()
        getData(3).then(data => {
            setValue3(data)
            compute()
            getData(4).then(data => {
                setValue4(data)
                compute()
            })
        })
    })
})

哈哈哈,看到这个代码笑出了声,不是说promise为了解决回调地狱吗,我用了呀,但是这不还是地狱吗?

也许现在也还有人这么写,其实我在写两层嵌套的时候也还是这么写,很顺手!!!!!

但其实应该解决的写法是

await/async 写法

其实就是之前demo敲的,异步变同步,这也是我认为await/async的核心作用(可能异步变同步这个说法有点问题,想不到什么好的描述)

try {
    const data1 = await getData(1)
    const data2 = await getData(2)
    const data3 = await getData(3)
    const data4 = await getData(4)
    setValue1(data1);
    setValue2(data2);
    setValue3(data3);
    setValue4(data4);
} catch (error) {
    console.error('Error fetching data:', error);
}

then写法

这样写才能说是解决回调地狱,让异步看起来像同步代码

getData(1).then(data1 => {
    setValue1(data1)
    compute()
    return getData(2)
}).then(data2 => {
    setValue2(data2)
    compute()
    return getData(3)
}).then(data3 => {
    setValue3(data3)
    compute()
    return getData(4)
}).then(data4 => {
    setValue4(data4)
    compute()
}).catch(err => {
    console.error('Error fetching data:', err);
})

两种的错误拦截

catch在某一个then出现错误都会触发,如果有需要知道是哪一个产生的报错,我目前是没有什么更优解决,只能说像这样

getData(1).then(data1 => {
    setValue1(data1)
    compute()
    return getData(2)
}).catch(err => {
    console.error('Error fetching data:', err);
}).then(data2 => {
    setValue2(data2)
    compute()
    return getData(3)
}).catch(err => {
    console.error('Error fetching data:', err);
}).then(data3 => {
    setValue3(data3)
    compute()
    return getData(4)
}).catch(err => {
    console.error('Error fetching data:', err);
}).then(data4 => {
    setValue4(data4)
    compute()
}).catch(err => {
    console.error('Error fetching data:', err);
})

async/await就比较好看一点

try {
    const data1 = await getData(1).catch(err => { console.error('Error fetching data1:', err); })
    const data2 = await getData(2).catch(err => { console.error('Error fetching data2:', err); })
    const data3 = await getData(3).catch(err => { console.error('Error fetching data3:', err); })
    const data4 = await getData(4).catch(err => { console.error('Error fetching data4:', err); })
    setValue1(data1);
    setValue2(data2);
    setValue3(data3);
    setValue4(data4);
} catch (error) {
    console.error('Error fetching data:', error);
}

不是什么技术文章,就记录一下脑子运转的过程,和demo敲出来的结论,下次可以不用再敲一遍