告别"回调地狱"!Promise让异步代码"一线生机"

什么是异步

我们都知道代码执行时,v8把这段代码先编译再运行,此时cpu就会接受一个指令来执行上下文环境,这时候用的时间就叫做进程。执行指令的时间就是一个线程,所以一个进程可以有多个线程。但是我们的v8编译器跟别的编程语言就有点不一样来看下面的代码。

ini 复制代码
 let a=1
setTimeout(()=>{
    a=2
},1000)
console.log(a);

如果按照正常的编译顺序这时候输出打印的a就是2,但是我们可以看到这时的结果是1。很显然,v8是直接先执行了第一行与第五行的代码把中间这个定时器挂起了。

那这是为什么呢?

js默认是单线程运行的(v8默认只会开一个主线程来跑js代码)

  1. 因为js设计之处是浏览器的脚本语言,设计成单线程可以节约用户的设备性能
  2. js代码中存在耗时执行的,会被v8挂起,先执行不耗时的(同步代码)

这时候这种编程方式我们就叫作异步

如何解决异步

1.回调函数(初级)

来看这段代码,首先肯定就是先执行不消耗时间的指令所以先输出打印baz,a再是其他另外两个,但是我有没有一种方法可以foo先执行再是bar最后baz呢?

javascript 复制代码
let a=1
function foo(){
    setTimeout(()=>{
        a=2
        
        console.log('foo',a);
        
    
    },1000)
}
function bar(){
    setTimeout(()=>{
        a=3
        
        console.log('bar',a);
        
    
    },2000)
}
function baz(){
    console.log('baz',a);
}
foo()

这时候我们就可以用到回调函数,把baz放进bar里面,把bar放进foo里面,形成一个嵌套。

scss 复制代码
let a=1
function foo(){
    setTimeout(()=>{
        a=2
        bar()
        console.log('foo',a);
        
    
    },1000)
}
function bar(){
    setTimeout(()=>{
        a=3
        baz()
        console.log('bar',a);
        
    
    },2000)
}
function baz(){
    console.log('baz',a);
}
foo()

但是如果代码这样写的话,代码量大的话,就容易嵌套过深,形成回调地狱,我们维护代码时难以维护,一个函数有问题,一整个代码运行不了。所以这种方法虽然可行但是还是不够完美。

2.promise解决异步(高级)

我们用promise来以一个更加优雅的方式来解决这个问题,来看代码

javascript 复制代码
let a=1
function foo(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
        a=2
        console.log('foo',a);
        resolve()
    },2000)
    })
}
function bar(){
   return new Promise((resolve,reject)=>{
     setTimeout(()=>{
        a=3
        
        console.log('bar',a);
        resolve()
    },1000)
   })
}
function baz(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
        a=4
     console.log('baz',a);
     resolve() 
    },500)
    })
    
}
foo().then(()=>{
    return bar()
})
.then(()=>{
    return baz()
})

在三个函数加入promise Promise 有三种状态:

  1. pending(进行中) - 初始状态
  2. fulfilled(已成功) - 操作成功完成
  3. rejected(已失败) - 操作失败、

Promise 创建后会立即执行 这时候每个promise对象的状态会被修改为成功,而.then顾名思义就是下一个,执行完函数里的再执行.then。而then源码也默认返回了一个promise对象,状态继承了前面的foo。return 让 then 返回的promise状态根据bar返回的promise状态改变

3.Async/Await(进阶)

这里这样写虽然和promise差不多区别就在于最后把then换成了async,await.

  • 函数前面加一个async等同于函数内部返回一个promise实例对象

  • await 必须跟async 配合使用,并且await后面如果不接一个promise对象,await无法约束它

  • await fn() 把 fn() 当成同步看待

javascript 复制代码
let a=1
function foo(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
        a=2
        console.log('foo',a);
        resolve()
    },2000)
    })
}
function bar(){
   return new Promise((resolve,reject)=>{
     setTimeout(()=>{
        a=3
        
        console.log('bar',a);
        resolve()
    },1000)
   })
}
function baz(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
        a=4
     console.log('baz',a);
     resolve() 
    },500)
    })
    
}
async function fn(){
    await foo()
    await bar()
    baz()
}
fn()

总结:异步编程的"思想升华"

JavaScript的异步演进,就像人类处理多任务的智慧成长:

  1. 原始时代(回调) :一件事一件事做,记在脑子里(嵌套)
  2. 农业时代(Promise) :用记事本记下待办事项(任务队列)
  3. 信息时代(Async/Await) :用智能助手管理所有任务(自动化调度)

记住这三个核心点:

  1. JavaScript是单线程,但不代表它慢 ------ Event Loop让它高效处理并发
  2. Promise不是魔法,是一种状态管理机制 ------ 三种状态,两种结果
  3. Async/Await是语法糖,不是新东西 ------ 底层依然是Promise
相关推荐
程序员Sunday2 小时前
TypeScript 的 any、unknown、never 有什么区别?
前端·面试·typescript
朱涛的自习室2 小时前
70 美金的 Beyond Compare,我让 Gemini 4 和 DeepSeek 造个开源免费版(Day 2)
android·前端·人工智能
码艺-Alimjan3 小时前
Tauri 源码备份 · 打包 & 解压 总结,源码收集之路
前端·javascript·vue.js
小马不起床3 小时前
零基础玩转 FastAPI_11:前端后台管理页面
前端·状态模式·fastapi
子非鱼a4 小时前
【文件上传】一个普普通通的edu16
前端
美狐美颜SDK开放平台4 小时前
直播APP如何实现美白滤镜功能?视频美颜SDK技术开发方案详解
前端·数据库·人工智能·音视频·美颜sdk·直播美颜sdk·视频美颜sdk
pride.li5 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
屏什么录5 小时前
电脑如何录屏幕视频和声音?从工具到代码,7 种方案帮你彻底搞定
前端·音视频开发
DevUp5 小时前
标着 JavaScript 的 Wiki 与知识库:既不是 CMS 也不是 SSG(番外三)
javascript·node.js·cms
用户360055579005 小时前
Kestrel_VLLM_CUDA -09 · full-GPU decode:单 token 全设备
前端