关于JavaScript中Async与Promise的技术疑问
JavaScript Async 与 Promise 常见疑问解答
1. JavaScript是否只能通过XMLHttpRequest、DOM、setTimeout这类Web API/函数实现异步执行?
不是。JS的异步核心是事件循环,只要能把任务放到宏任务或微任务队列里,就能实现异步。除了你提到的Web API,还可以用:
Promise、async/await(本质是Promise的语法糖)queueMicrotask()直接创建微任务- Node.js环境下的
fs.promises、child_process等内置异步API
不需要局限于特定的几个Web API。
2. 我们能否自定义异步执行的函数?
当然可以,有两种常见方式:
- 写一个返回
Promise的函数,在内部控制异步逻辑 - 用
async关键字定义函数(这类函数默认返回Promise,配合await使用更简洁)
示例代码:
// 方式1:返回Promise function delay(ms) { return new Promise(resolve => { setTimeout(() => resolve(`延迟${ms}ms完成`), ms); }); } // 方式2:async函数 async function fetchData() { await delay(1000); return "模拟获取的数据"; }
3. 自定义的Promise函数是否会异步执行?
要看具体实现:
Promise构造函数的执行器函数(也就是你传入的(resolve, reject) => {})是同步执行的,创建Promise时就会立刻跑这部分代码- 但
then()、catch()、finally()里的回调是异步微任务,会等同步代码执行完才运行
如果想让自定义函数的核心逻辑异步,得把耗时操作放到Web API(比如setTimeout)或queueMicrotask里,避免阻塞主线程。
4. 如下示例代码的输出顺序为HELLO、WORLD、FROM PROMISE,是否说明这段代码是异步执行的?
// Example, does the code run asynchronously? function showText() { return new Promise((resolve) => { resolve("FROM PROMISE"); }); } console.log("HELLO"); showText().then((res) => console.log(res)); console.log("WORLD"); // Output // HELLO // WORLD // FROM PROMISE
是的,这段代码的异步特性体现在then()的回调上,执行流程是:
- 同步打印
HELLO - 调用
showText(),执行器同步调用resolve,将Promise设为完成状态,同时把then()的回调加入微任务队列 - 同步打印
WORLD - 所有同步代码执行完毕,事件循环处理微任务队列,执行
then()回调打印FROM PROMISE
正是因为then()回调是异步的,才会出现WORLD在FROM PROMISE之前输出的顺序。
5. 如下示例代码中,为何WORLD没有立即输出,而是和count函数的结果几乎同时出现?
function count() { // imagine this function is heavy and take a time to run it return new Promise((resolve, reject) => { let num = 0; for (let i = 1; i <= 10000000000; i++) { num += 1; } resolve(num); }); } console.log("HELLO"); count().then((res) => console.log(res)); console.log("WORLD"); // Output // HELLO // WORLD // 10000000000
核心原因是:count()里的超大for循环是同步执行的!
Promise的执行器函数会在创建Promise时立刻同步运行,这个循环耗时极长,直接阻塞了主线程。在循环结束前,后面的console.log("WORLD")根本没机会执行。完整流程是:
- 同步打印
HELLO - 调用
count(),立刻执行执行器里的for循环,主线程被卡住 - 循环结束后,调用
resolve(num),then()回调被加入微任务队列 - 主线程从
count()返回,才执行console.log("WORLD") - 同步代码执行完毕,处理微任务队列,打印
10000000000
所以你看到WORLD和结果几乎同时出现,是因为WORLD必须等循环结束才能打印,而结果紧接着从微任务输出。如果想让count逻辑真正异步,得把循环放到Web API(比如setTimeout)或Worker线程里,避免阻塞主线程。
内容的提问来源于stack exchange,提问作者mrr dev
相关产品推荐
相关产品推荐

