告别"回调地狱"!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
相关推荐
小小19926 分钟前
idea 配置less转化为css
前端·css·less
hhb_6188 分钟前
Less嵌套避坑:优先级冲突实战解析
前端·css·less
快乐的哈士奇12 分钟前
【Next.js实战①】Gmail API 按柜号检索邮件:OAuth 双 Cookie 与搜索 Fallback
开发语言·javascript·ecmascript
云水一下18 分钟前
Vue.js从零到精通系列(五):全局状态管理——Pinia 核心与实践
前端·javascript·vue.js
我不是外星人26 分钟前
浅谈我对 AI 发展的看法
前端·ai编程·claude
kmblack11 小时前
javascript计算年龄
开发语言·javascript·ecmascript
甲维斯1 小时前
测一波Kimi K2.7,消耗一周配额!
前端·人工智能·游戏开发
Dick5071 小时前
ROS2 多机器人通用 Driver 层复盘:BaseRobotDriver 到多平台 Mock 切换实现
前端·javascript·机器人
xiaofeichaichai2 小时前
前端安全 XSS 与 CSRF
前端·安全·xss