告别"回调地狱"!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
相关推荐
FinClip1 小时前
当豆包手机刷屏时,另一场“静悄悄”的变革已经在你手机里发生
前端
前端老宋Running1 小时前
“求求你别在 JSX 里写逻辑了” —— Headless 思想与自定义 Hook 的“灵肉分离”术
前端·javascript·程序员
阿珊和她的猫1 小时前
深入理解 HTML 中 `<meta>` 标签的 `charset` 和 `http-equiv` 属性
前端·http·html
alamhubb1 小时前
前端终于不用再写html,可以js一把梭了,我的ovs(不写html,兼容vue)的语法插件终于上线了
javascript·vue.js·前端框架
syt_10131 小时前
gird布局之九宫格布局
前端·javascript·css
BD_Marathon1 小时前
【JavaWeb】HTML_常见标签_布局相关标签
前端·html
SelectDB技术团队1 小时前
云上数据安全新范式:Apache Doris IAM Assume Role 解锁无密钥访问 AWS S3 数据
服务器·前端·安全
m0_740043731 小时前
Vue 组件中获取 Vuex state 数据的三种核心方式
前端·javascript·vue.js
Hashan1 小时前
基于Vue3完成动态组件库建设
前端