同步:函数执行结束立刻有返回值,函数后面的代码需要等待函数有返回值之后才能执行
function sum (a,b) {
console.log(a+b)
return a+b;
}
sum(1,2);
console.log(1);
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LleH3r9G-1666525610168)(同步.png)]](https://1000bd.com/contentImg/2024/05/24/054129ac4ba47582.png)
异步:函数执行结束需要等待某个条件满足之后才有返回值,函数后面的代码无需等待函数有返回就能执行
setTimeout(function(){
console.log(1)
},1000)
cosnole.log(2)
var btn = docment.querySelector('button');
btn.onclick = function(){
console.log(1)
}
console.log(2)
执行js代码的时候,遇见同步任务,直接推入调用栈中执行,遇到异步任务,将该任务挂起,等到异步任务有返回之后推入到任务队列中,当调用栈中的所有同步任务全部执行完成,将任务队列中的任务按顺序一个一个的推入并执行








setTimeout(function(){
console.log(1)
},1000)
cosnole.log(2)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AyeSw9TS-1666525610169)(异步.png)]](https://1000bd.com/contentImg/2024/05/24/fe8e0ebb141c7aeb.png)
var btn = docment.querySelector('button');
btn.onclick = function(){
console.log(1)
}
console.log(2)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8kREIx0R-1666525610170)(dom事件异步.png)]](https://1000bd.com/contentImg/2024/05/24/8d008444f871b3ad.png)
**浏览器进程。**主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。
**渲染进程。**核心任务是将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页,排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该进程中,默认情况下,Chrome 会为每个 Tab 标签创建一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下。
**GPU 进程。**其实,Chrome 刚开始发布的时候是没有 GPU 进程的。而 GPU 的使用初衷是为了实现 3D CSS 的效果,只是随后网页、Chrome 的 UI 界面都选择采用 GPU 来绘制,这使得 GPU 成为浏览器普遍的需求。最后,Chrome 在其多进程架构上也引入了 GPU 进程。
**网络进程。**主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程。
**插件进程。**主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响。
var xhr = new XMLHttpRequest();
xhr.open('GET', 'demo-data', true);
xhr.send();
xhr.onreadystatechange = function (e) {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
console.log(2);
}
};
console.log(1)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RJa8L3vY-1666525610170)(ajax异步.png)]](https://1000bd.com/contentImg/2024/05/24/7a955439668986a1.png)
var a = 1;
function sum (a,b) {
console.log(1)
return a+b;
}
sum(1,2);
setTimeout(function(){
console.log(2)
},1000)
cosnole.log(3)
var btn = docment.querySelector('button');
btn.onclick = function(){
console.log(1)
}
console.log(2)
消息队列中的任务类型
消息队列中的任务分成:
**宏任务:**消息队列中的任务称为宏任务,每个宏任务中都包含了一个微任务队列。
**微任务:**等宏任务中的主要功能都完成后,渲染引擎不急着去执行下一个宏任务,而是执行当前宏任务中的微任务

| 宏任务(macrotask) | 微任务(microtask) | |
|---|---|---|
| 谁发起的 | 宿主(Node、浏览器) | JS引擎 |
| 具体事件 | 1. 执行script标签内部代码 2.setTimeout/setInterval 3. ajax请求 4.postMessageMessageChannel 5. setImmediate,I/O(Node.js) | 1. Promise 2. MutaionObserver 3. Object.observe 4.process.nextTick(Node.js) |
setTimeout(()=>{console.log(3)},0)
new Promise(function(resolve,reject){
console.log(1);
resolve('fullied')
}).then(function(data){
console.log(data)
})
console.log(2)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rPnFeWwj-1666525610171)(微任务.png)]](https://1000bd.com/contentImg/2024/05/24/2a260fcf2c8d4e70.png)
第一是嵌套调用,下面的任务依赖上个任务的请求结果,并在上个任务的回调函数内部执行新的业务逻辑,这样当嵌套层次多了之后,代码的可读性就变得非常差了。
第二是任务的不确定性,执行每个任务都有两种可能的结果(成功或者失败),所以体现在代码中就需要对每个任务的执行结果做两次判断,这种对每个任务都要进行一次额外的错误处理的方式,明显增加了代码的混乱程度
function ajax(request, resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(request.method, request.url, request.sync);
xhr.send();
xhr.onreadystatechange = function (e) {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
resolve(xhr.response)
} else {
reject('error')
}
}
};
}
ajax({ method: 'GET', url: '/1', sync: true }, function (success) {
console.log('success1:' + success)
ajax({ method: 'GET', url: '/2', sync: true }, function (success) {
console.log('success2:' + success)
ajax({ method: 'GET', url: '/3', sync: true }, function (success) {
console.log('success3:' + success)
}, function (error) {
console.log('error:' + error)
})
}, function (error) {
console.log('error:' + error)
})
}, function (error) {
console.log('error:' + error)
})
第一是消灭嵌套调用;
第二是合并多个任务的错误处理。
function xFetch(request) {
function ajax(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(request.method, request.url, request.sync);
xhr.send();
xhr.onreadystatechange = function (e) {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
resolve(xhr.response)
} else {
reject('error')
}
}
};
}
return new Promise(ajax)
}
var p1 = xFetch({ method: 'GET', url: '/1', sync: true });
var p2 = p1.then(function(success){
console.log(success);
return xFetch({ method: 'GET', url: '/2', sync: true });
})
var p3 = p2.then(function(success){
console.log(success);
return xFetch({ method: 'GET', url: '/3', sync: true });
})
p3.then(function(success){
console.log(success);
})
p3.catch(function(error){
console.log(error)
})
async await实现是通过Generator(生成器)和promise两种技术
Generator 的底层实现机制——协程(Coroutine)
协程是一种比线程更加轻量级的存在。你可以把协程看成是跑在线程上的任务,一个线程上可以存在多个协程,但是在线程上同时只能执行一个协程,比如当前执行的是 A 协程,要启动 B 协程,那么 A 协程就需要将主线程的控制权交给 B 协程,这就体现在 A 协程暂停执行,B 协程恢复执行;同样,也可以从 B 协程中启动 A 协程。通常,如果从 A 协程启动 B 协程,我们就把 A 协程称为 B 协程的父协程。
function* genDemo() {
console.log("开始执行第一段");
yield 'generator 2';
console.log("开始执行第二段");
yield 'generator 2';
console.log("开始执行第三段");
yield 'generator 2';
console.log("执行结束");
return 'generator 2'
}
console.log('main 0');
let gen = genDemo();
console.log(gen.next().value);
console.log('main 1');
console.log(gen.next().value);
console.log('main 2');
console.log(gen.next().value);
console.log('main 3');
console.log(gen.next().value);
console.log('main 4')

async函数返回一个promise
async function foo(){
return 1
}
console.log(foo())
async function foo() {
console.log(1);
let a = await 100;
console.log(a);
console.log(2)
}
console.log(0);
foo();
console.log(3)
当执行到await 100时,会默认创建一个 Promise 对象,代码相当于
let promise_ = new Promise((resolve,reject){
resolve(100)
})
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OABRSfpu-1666525610171)(async await.png)]](https://1000bd.com/contentImg/2024/05/24/9dd7d21a56f5421b.png)

promise语法
const p1 = new Promise((reslove,reject)=>{
console.log(2);
reslove(1)
}).then((data)=>{
console.log(3);
}).catch((data)=>{
console.log(3);
})
2. 三种状态
pending: 在过程中还没有结果
fulfilled: 已经解决了
rejected:被拒绝了,失败了
3. 状态的变化和表现
(1)状态一旦生成,不会因为后面再调用的resolve或者reject而改变
(2)不执行resolve或者reject就一直是pending状态,pending不会触发then和catch
(3) resolve 方法的参数是then中回调函数的参数
reject 方法中的参数是catch中的参数
(4) Promise.resolve()返回fulfilled状态的promise
Promise.rejetc()返回rejected状态的promise
(5) then 和 catch 只要不报错,返回的都是一个fullfilled状态的promise
promise.all 基本语法
Promise.all([p1, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error)
})
promise特点
使用场景: 如果有一个接口需要等待,页面上两个接口都返回数据才调用,有一个失败就不调用的情况
思路:
1、接收一个 Promise 实例的数组或具有 Iterator 接口的对象,
2、遍历每一个数组元素,如果元素不是 Promise 对象,则使用 Promise.resolve 转成 Promise 对象
3、如果全部成功,状态变为 resolved,返回值将组成一个数组传给回调
4、只要有一个失败,状态就变为 rejected,返回值将直接传递给回调all()
的返回值也是新的 Promise 对象
function promiseAll(promises) {
return new Promise(function (resolve, reject) {
if (!Array.isArray(promises)) {
return reject(new TypeError('arguments must be an array'));
}
var resolvedCounter = 0;
var promiseNum = promises.length;
var resolvedValues = new Array(promiseNum);
for (let i = 0; i < promiseNum; i++) {
Promise.resolve(promises[i]).then(function (value) {
resolvedCounter++
resolvedValues[i] = value
if (resolvedCounter == promiseNum) {
return resolve(resolvedValues)
}
}, function (reason) {
return reject(reason)
})
}
})
}
基本语法
Promise.race([p1, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 打开的是 'failed'
})
特点:Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态
思路:
返回一个创建的promise,在该promise的then中遍历每一个数组元素,并且当
某个元素有返回,直接执行创建的promise的resolve/reject
function promiseRace(promises) {
if (!Array.isArray(promises)) {
throw new Error("promises must be an array")
}
return new Promise(function (resolve, reject) {
promises.forEach(p =>
Promise.resolve(p).then(data => {
resolve(data)
}, err => {
reject(err)
})
)
})
}
async function async1(){
console.log('async1 start');
await async2();
console.log('async1 end');
}
await关键字只能在async函数中使用
await 后面跟着的应该是一个promise对象
await 表示在这里等待promise返回结果了,再继续执行。
await 相当于promise的then情况,所以promise返回catch没办法处理,所以捕获问题需要配合trycatch使用