前言:
JavaScript
是一个单线程的语言,因此它并不能像Java一样并发地执行2多个任务。只能一个接一个地按照JavaScript
规定好的顺序去执行。
但我们都知道的是有些程序(定时器、AJAX
请求等)是需要一定时间等待后才能执行的,当我们将需要耗时的代码块写在不需要耗时的代码块前时,会产生阻塞,为了避免这种情况的发生JavaScript
背后有一套属于自己的执行机制。
事件循环Event Loop
在介绍Event Loop
之前,首先我们需要知道什么是异步什么是同步。
同步任务:
在 JavaScript
中,同步操作是指代码按照书写的顺序依次执行,每一行代码必须等待前一行代码执行完成后才能开始执行。这就像一个排队的过程,一个任务完成后才会开始下一个任务。同步操作会阻塞后续代码的执行,直到当前操作完成
异步任务:
异步操作是指代码不会按照书写顺序立即执行,而是在某个特定的事件发生或者某个条件满足后才会执行。这使得 JavaScript 能够在执行一个长时间运行的任务(如网络请求、定时器等)时,不会阻塞其他代码的执行。异步操作通常涉及到回调函数、Promise
、async/await
等机制。
console.log(111);
setTimeout(() => {
console.log(222);
}, 1000)
console.log(333);
如上图所示setTimeout
是一个十分经典的异步任务,需要一定的时间去执行。
Event Loop
Event Loop
(事件循环)是 JavaScript
的一种运行机制,用于处理异步操作。在 JavaScript
中,代码的执行是单线程的,这意味着同一时间只能执行一个任务。但是,实际的应用场景中有很多异步操作,如网络请求、定时器、用户交互事件等。Event Loop
的作用就是协调这些异步操作的执行顺序,使得 JavaScript
能够高效地处理多个任务而不会阻塞主线程。接下来需要了解任务分为以下两种任务的。
宏任务与微任务
如上上述,js的代码分成了同步代码与异步代码,而在这基础之上异步代码可以被理解为一个任务,任务又被分成了两大类分别是宏任务与微任务。
任务 | 任务类型 |
---|---|
JavaScript | 宏任务 |
事件 | 宏任务 |
AJAX | 宏任务 |
readFile读取文件 | 宏任务 |
promise | 微任务 |
async/await | 微任务 |
Promise
Promise
是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。有了Promise
对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。
const promise = new Promise(function (resolve, reject) { });
Promise
构造函数接受一个函数作为参数,该函数的两个参数分别是resolve
和reject
。它们是两个函数,由 JavaScript
引擎提供,不用自己部署。
resolve与reject
resolve
函数的作用是,将Promise
对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject
函数的作用是,将Promise
对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
then
方法可以接受两个回调函数作为参数。第一个回调函数是Promise
对象的状态变为resolved
时调用,第二个回调函数是Promise
对象的状态变为rejected
时调用。这两个函数都是可选的,不一定要提供。它们都接受Promise
对象传出的值作为参数。
then
方法是promise
原型上的一个函数,x.then() then
函数会在x这个promise
实例对象状态变更为resolved
之后才执行内部逻辑,由此借助这个机制可以将异步捋成同步
例子:
接下来举一个简单的例子,让我们看看promise
到底是如何进行使用的
function home() {
setTimeout(() => {
console.log('回家了');
})
}
function eat() {
setTimeout(() => {
console.log('吃饭');
}, 1000)
}
function sleep() {
console.log('睡觉');
}
home()
eat()
sleep()
如上代码所示,很明显,我们希望实现的功能是,先回家再吃饭最后睡觉,但正常执行最终得不到我们想要的结果,此时便可用上promise来对这些异步代码进行操作了。
function home() {//promise对象有三种状态status:分别为:pending resloved rejected
return new Promise((resolve, reject) => {
//默认为status=pending
setTimeout(() => {
console.log('回家了');
//此时status变为resolve
resolve()
}, 2000)
})
}
function eat() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('吃饭');
resolve()
}, 1000)
})
}
function sleep() {
console.log('睡觉');
}
//只有status变为resloved时,.then函数才会被调用
home().then(() => {
eat().then(() => {
sleep()
})
})
//第二种写法:
home()
.then(() => {
return eat()
})
//如果.then函数没有主动返回一个promise对象,则主动返回由
.then(() => {
sleep()
})
只有当status变为了resolve时,才会使得.then被接收。resolve()会使得status的状态变为resolve,而reject()则会使得status的状态变为reject,最后会被.then或.catch接收。