You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

异步JavaScript:如何同时运行两个函数并优化执行顺序?

异步JavaScript任务调度问题解答

问题详情

我正在加深对异步JavaScript的理解,编写了一个耗时的计数函数,处理不当会阻塞其他代码执行。测试时,第一个函数从1计数到10000000,第二个从10计数到100。

测试代码

async function LongTask(from, to) {
    //Count up
    let myNum = from
    console.log(`counting from ${myNum} to ${to}`)
    let start = new Date();

    while (myNum != to) {
        //console.log(`myNum: ${myNum}`);
        await myNum++;

    }
    let end = new Date();
    console.log(`counting from ${from} to ${to} done in ${end - start}ms!`);
}

//2 functions that take some time to finish
LongTask(1, 10000000);
LongTask(10, 100);

//Do unrelated stuff
console.log("Hello World!");

输出结果

counting from 1 to 10000000
counting from 10 to 100
Hello World!
counting from 10 to 100 done in 2ms!
counting from 1 to 10000000 done in 40389ms!

疑问

目前通过await myNum++实现了短任务(10到100)先完成,但第10行的await myNum++出现警告:'await' has no effect on the type of this expression。若移除await关键字,代码会阻塞,短任务需等待长任务执行完毕才能启动。是否误解了异步JavaScript的工作原理?有没有更优的方法确保短任务优先完成?


分析与解决方案

核心误解

你对await的用法确实存在偏差:await的作用是等待Promise对象的状态变更,而myNum++是同步数值运算,返回的是数字而非Promise。这里await能“生效”是因为JavaScript会自动将非Promise值包装为已resolve的Promise,每次await都会让当前任务暂停,把执行权交还给事件循环,给其他任务执行机会。但这种写法既不规范,还会引发大量不必要的事件循环切换,性能损耗严重。

正确的异步拆分方式

要避免阻塞事件循环,同时让短任务优先执行,需将长任务拆分为多个小任务片段,每执行一段就主动交出执行权,让事件循环调度其他任务。推荐用await Promise.resolve()实现这一点,代码示例:

async function LongTask(from, to) {
    let myNum = from;
    console.log(`counting from ${myNum} to ${to}`);
    let start = new Date();

    while (myNum !== to) {
        myNum++;
        // 每执行10000次就交出执行权,平衡性能与响应性
        if (myNum % 10000 === 0) {
            await Promise.resolve();
        }
    }

    let end = new Date();
    console.log(`counting from ${from} to ${to} done in ${end - start}ms!`);
}

LongTask(1, 10000000);
LongTask(10, 100);
console.log("Hello World!");

原理说明

JavaScript是单线程模型,所有同步代码会持续占用事件循环直至执行完毕。通过await Promise.resolve(),我们把长任务拆成多个小同步块,每个块执行完后,事件循环可以优先处理短任务的同步块(因为短任务总工作量小),从而实现短任务先完成的效果,同时不会阻塞其他代码执行。

进阶调度思路

如果需要更精细的优先级控制,可以维护一个优先级任务队列,利用微任务机制(如queueMicrotask)在事件循环空闲时优先执行高优先级任务片段。但针对当前场景,上述拆分方法已足够解决问题。


内容的提问来源于stack exchange,提问作者Curtis_L

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 16:05:53