进程-线程-事件循环

2022-09-30  本文已影响0人  未路过

19.1 进程和线程

161.PNG 162.PNG 163.PNG

19.2 浏览器中的Javascript线程

浏览器的每一个tab页面就会开启一个新的进程,这个进程里面有包括执行js代码的单线程,也有执行其他操作的线程。比如网络请求,定时器什么的都是其他线程执行的。js单线程就是指同一时刻只能执行一段,一行js代码。不能同时执行不同行的js代码。

164.PNG

19.3 浏览器的事件循环

165.PNG 167.PNG
console.log("script start")

// 业务代码
setTimeout(function() {

}, 1000)
//定时器函数,是全局函数,这个函数本身不是异步操作,是同步,像foo函数被调用一样
//是同步调用,但是setTimeout需要传进去一个回调函数,一般说的异步函数,是指的是传进去的这个函数
/* 
传进去的这个函数不是立即执行,1s之后执行,
浏览器的其他线程帮助我们开始计时操作,
js线程是单线程的,如果计时的话,其他就不能操作了。
这个回调函数会保存到js的其他线程,
js线程不用管你,开始执行其他行的代码
等到1s中的时候,开始执行回调函数
这个时候是有一个队列的,浏览器本身维护着一个队列queue(事件队列)
队列是一种数据结构,是先进先出。跟栈结构相反,
队列默认没有东西,当计时器达到1s后,会将回调函数放到队列里面
当js引擎发现队列有东西,就会从队列里面取出我们要执行的回调函数
开始做执行

网络请求,settimeout,dom操作都可以依次加到队列里面

加到队列后,从队列里面挨个取出函数并且调用,在js里面执行,

真正执行的位置还是js的线程。

一般情况下,
js线程,浏览器的其他线程,浏览器维护的事件队列
这三个东西形成了一个闭环。

回调函数之类的放到浏览器的其他地方做一些耗时操作,
耗时操作结束之后,会将回调函数加入到队列里面
js线程再从队列里面获取到要执行的回调函数,开始进行执行

这个闭环,就被我们成为事件循环

无论是网络请求,还是settimeout都是由js线程发起的,
然后再js的其他线程做耗时操作,并且加到队列里面,最后再返回js线程执行
*/

console.log("后续代码~")


console.log("script end")

19.4 宏任务和微任务

166.PNG
setTimeout(() => {
  console.log("setTimeout")
}, 1000)
//setTimeout是先放到浏览器的其他线程,等到时间之后,加入到队列里面

queueMicrotask(() => {
  console.log("queueMicrotask")
})
//queueMicrotask是直接加入到队列里面,并且和settimeout加入的是不同的队列

/* 

宏任务队列(macrotask queue):ajax、setTimeout、setInterval、DOM监听、UI Rendering等
微任务队列(microtask queue):Promise的then回调、 Mutation Observer API、queueMicrotask()等

规范:
当两个队列里面都有任务的时候,
在执行任何的宏任务之前,都需要先保证微任务队列已经被清空



*/


Promise.resolve().then(() => {
  console.log("Promise then")
})


//以下是main script 全局代码,优先执行
function foo() {
  console.log("foo")
}

function bar() {
  console.log("bar")
  foo()
}

bar()

console.log("其他代码")

19.5 面试题

1.面试题1

setTimeout(function () {
  console.log("setTimeout1");
  new Promise(function (resolve) {
    resolve();
  }).then(function () {
    new Promise(function (resolve) {
      resolve();
    }).then(function () {
      console.log("then4");
    });
    console.log("then2");
  });
});

new Promise(function (resolve) {
  console.log("promise1");
  resolve();
}).then(function () {
  console.log("then1");
});

setTimeout(function () {
  console.log("setTimeout2");
});

console.log(2);

queueMicrotask(() => {
  console.log("queueMicrotask1")
});

new Promise(function (resolve) {
  resolve();
}).then(function () {
  console.log("then3");
});


/* 
new Promise((resolve, reject) => {
  ...
})

在这里,
(resolve, reject) => {
  ...
}
这个回调函数是不会被加进任务队列的,是会直接执行的
相当于里面代码...在main script里面执行的
后面的then里面的回调是会被加入进微任务队列的
等到下面单线程的代码运行完之后才能够执行

*/
/* 

"promise1"
2
then1
queueMicrotask1
then3
setTimeout1
"then2"
then4
setTimeout2
*/


/* 

执行完微任务之后,执行
setTimeout(function () {
  console.log("setTimeout1");
  new Promise(function (resolve) {
    resolve();
  }).then(function () {
    new Promise(function (resolve) {
      resolve();
    }).then(function () {
      console.log("then4");
    });
    console.log("then2");
  });
});

先输出"setTimeout1",之后,直接执行function (resolve) {
    resolve();
  }
  然后,把这个回调函数
  function () {
    new Promise(function (resolve) {
      resolve();
    }).then(function () {
      console.log("then4");
    });
    console.log("then2");
  }
  加入到微任务中
  这时候,就剩下了微任务中的这个,还有宏任务中的setTimeout2
  在执行宏任务之前,要保证微任务里面没有东西,
  所以需要先执行上面的回调
  执行resolve(),然后再把then4加入到微任务
  然后再继续往后,执行then2
  接下来再执行then4,后面执行settimeout2

*/

[图片上传失败...(image-f5de6d-1664549933477)]

2.面试题2

 async function bar() {
   console.log("22222")
  return new Promise((resolve) => {
     resolve()
   })
 }

 async function foo() {
   console.log("111111")

   await bar()

   console.log("33333")
 }

 foo()
 console.log("444444")

 /* 
 
 111111
test2.html:15 22222
test2.html:30 444444
test2.html:26 33333
 */

async function async1 () {
  console.log('async1 start')
  await async2();
  console.log('async1 end')
}

async function async2 () {
  console.log('async2')
}

console.log('script start')

setTimeout(function () {
  console.log('setTimeout')
}, 0)
 
async1();
 
new Promise (function (resolve) {
  console.log('promise1')
  resolve();
}).then (function () {
  console.log('promise2')
})

console.log('script end')


/* 
script start
'async1 start'
async2
'promise1'
'script end
async1 end
promise2
setTimeout
*/

3.面试题3

Promise.resolve().then(() => {
  console.log(0);
    // 1.直接return一个值 相当于resolve(4)

  return 4
}).then((res) => {
  console.log(res)
})

Promise.resolve().then(() => {
  console.log(1);
}).then(() => {
  console.log(2);
}).then(() => {
  console.log(3);
}).then(() => {
  console.log(5);
}).then(() =>{
  console.log(6);
})

/* 
0
1
4
2
3
5
6

*/
Promise.resolve().then(() => {
  console.log(0);
   // 2.return thenable的值
  return {
    then: function(resolve, reject){
      resolve(4)
    }
  }
  //,本来是直接resolve(4)的,但是因为是thenable,执行这个then函数被放到了下一次的为任务中
}).then((res) => {
  console.log(res)
})

Promise.resolve().then(() => {
  console.log(1);
}).then(() => {
  console.log(2);
}).then(() => {
  console.log(3);
}).then(() => {
  console.log(5);
}).then(() =>{
  console.log(6);
})

/* 
0
1
2
4
3
5
6

*/
Promise.resolve().then(() => {
  console.log(0);
 // 3.return Promise
  // 不是普通的值, 多加一次微任务
  // Promise.resolve(4), 多加一次微任务
  // 一共多加两次微任务
  return Promise.resolve(4)
}).then((res) => {
  console.log(res)
})

Promise.resolve().then(() => {
  console.log(1);
}).then(() => {
  console.log(2);
}).then(() => {
  console.log(3);
}).then(() => {
  console.log(5);
}).then(() =>{
  console.log(6);
})

/* 
0
1
2
3
4
5
6

*/

19.6 Node中的事件循环

169.PNG 170.PNG

19.7 Node事件循环的阶段

171.PNG 172.PNG
173.PNG 174.PNG
上一篇下一篇

猜你喜欢

热点阅读