进程和线程
进程
- 程序的运行环境(相当于生产的工厂)
线程
- 线程是实际进行运算的东西(相当于工厂里的工人)
同步
function sum(a, b){
return a + b
}
console.log("第一行打印")
let result = sum(123, 456)
console.log(result)
console.log("第二行打印")
- 代码自上而下一步一步运行
- 前边代码不执行后边的代码也不会执行
- 同步的代码执行会出现阻塞的情况
- 一行代码慢会影响到整个程序的执行
解决同步问题:
- Java、Python通过多线程来解决
- node.js通过异步方式来解决
异步
- 一段代码的执行不会影响其他程序的执行
- 异步代码无法通过return来返回值(有时间差)——>解决这个问题所以用回调函数 基于“回调函数”的异步带来的问题
- 使用回调函数时会导致“回调地狱”的情况
- 代码可读性差
- 可调式性差
function sum(a, b){
setTimeout(()=>{
return a + b
}, 10000)
}
console.log("第一行打印")
let result = sum(123, 456)
console.log(result) //undefined
console.log("第二行打印")
function sum(a, b, cb){
setTimeout(()=>{
cb(a + b)
}, 10000)
}
console.log("第一行打印")
sum(123, 456, result => {
console.log(result)
})
console.log("第二行打印")
回调地狱(如下:)代码可读性低且不好调试【这个问题可以用Promise来解决】
function sum(a, b, cb){
setTimeout(()=>{
cb(a + b)
}, 10000)
}
sum(123, 456, result => {
sum(result, 777, result => {
sum(result, 888, result => {
sum(result, 999, result => {
console.log(result)
})
})
})
})
Promise
- Promise可以帮助我们解决异步中的回调函数的问题
- Promise就是一个用来存储数据的容器
它拥有着一套特殊的存取数据的方式
这个方式使得它里边可以存储异步调用的结果
创建Promise
创建Promise时,构造函数中需要一个函数作为参数
Promise构造函数的回调函数,它会在创建Promise时调用,调用时会有两个参数传递进去
const promise = new Promise(executor)
const promise = new Promise((resolve, reject) => {
//resolve和reject是两个函数,通过这两个函数可以向Promise中存储数据
//resolve在执行正常时存储数据,reject在执行错误时存储数据
//通过函数来向Promise中添加数据,好处就是可以用来添加异步调用的数据
setTimeout(()=>{
resolve('哈哈')
},2000)
})
读取Promise数据
-
可以通过Promise的实例方法then来读取Promise中存储的数据
-
then需要两个回调函数作为参数,回调函数用来获取Promise中的数据
通过resolve存储的数据,会调用第一个函数返回()
可以在第一个函数中编写处理数据的代码通过reject存储的数据,会调用第二个函数返回
可以在第一个函数中编写处理异常的代码
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("哈哈")
}, 10000)
})
promise.then((data) => {
console.log(data) // "哈哈"
})
- Promise中维护了两个隐藏属性:
- PromiseResult
- 用来存储数据
- PromiseState
- 记录Promise的状态(三种状态)
- state只能修改一次,修改以后永远不会再变
- pending
- fulfilled
- rejected
- PromiseResult
catch
- catch()用法和then类似,但是只需要一个回调函数作为参数
- catch()中的回调函数只会在promise被拒绝时才调用
Promise静态方法
- Promise.resolve() 创建一个立即完成的Promise
- Promise.reject()创建一个立即拒绝的Promise
- Promise.all([...]) 里面有一个错误所有错误都不返回
- Promise.allSettled([...])同时返回多个数据的结果(无论成功或失败)
- Promise.race() 会返回首先执行完的Promise,而忽略其他未执行完的Promise
- Promise.any() any会race类似,但是它只会返回第一个成功的Promise,如果所有的Promise都失败才会返回一个错误信息。
asyns和await.js
nodejs文档地址:nodejs.dev/en
- 通过async可以快速创建异步函数
- 异步函数的返回值会自动封装到一个Promise中返回
- 在async声明的异步函数中可以使用await关键字来调用异步函数
async function fn2(){
return 10
}
//此时fn2就是一个异步函数
//想要读到10要用then方法
fn2().then(r=>{
console.log(r)
})
await用来解决链式调用太多的问题
function sum(a,b) {
return new Promise(resolve => {
setTimeout(() => {
resolve(a+b)
}, 2000);
})
}
/*
async function fn3() {
sum(123,456)
.then(r => sum(r,8)
.then(r => sum(r,9)
.then(r => console.log(r)
}
*/
let result = await sum(123,456)
// await表示等待,当我们通过await去调用异步函数时,它会暂停代码的运行;直到异步代码执行有结果时,才会将结果返回
// 注意:await只能用于 async声明的异步函数中,或es模块的顶级作用域中
// await阻塞的是异步函数内部的代码,不会影响外部代码
// 通过await调用异步代码时,需要通过try-catch处理异常
// 如果async声明的异步函数中没有写await,那么它里边的代码就会依次执行
async function fn4() {
console.log(1)
/*
当我们使用await调用函数后,当前函数后边的所有代码
会在当前函数执行完毕后,被放入到微任务队伍里(范围在async里)
*/
await console.log(2)
console.log(3)
}
fn4()
console.log(4)
//结果:1 2 4 3