乐趣区

关于node.js:Nodejs学习总结事件循环

1. 介绍

事件循环机制是 Node.js 最重要的一部分之一。
为什么他这么重要呢?因为它解释了为什么 Node.js(单线程)能够是异步的,并且不会阻塞 IO。
Node.js 能够做到这些,离不开调用栈、音讯队列和 ES6 工作队列。

2. 调用栈

在执行 javascript 脚本的时候会程序执行,讲执行的函数依照程序入栈,执行完之后退出栈。
例子如下:

test1() {console.log('test1');
}
test2() {console.log('test2');
}
test3() {console.log('test3 start');
  test1();
  test2();
  console.log('test3 end');
}
test3();

执行这个脚本会失去如下后果:

test3 start
test1
test2
test3 end

调用栈依照一下顺序调用:
1. 调用 test3()

|__test3__|

2. 执行 test3()

|__console.log(“test3 start”)__|
|__________test3___________ |

3.test1() 入栈并执行

|__console.log(“test1”)__|
|______test1___________|
|______test3___________|

test1 执行完之后退栈

4.test2() 入栈并执行

|__console.log(“test2”)__|
|______test2___________|
|______test3___________|

test2 执行完之后退栈

5. 继续执行 test3

|__console.log(“test3 end”)__|
|__________test3___________|

test3 执行完之后退栈

3. 音讯队列

如果只应用一个调用栈,那么当一个函数执行工夫很长时,这个函数会阻塞前面的须要被调用的函数。
因而,将那些会阻塞其余失常函数执行的函数(用户发动的事件)放在音讯队列中,如定时器、单击或键盘事件、Dom 事件。

例子:

test1() {console.log('test1');
}
test2() {console.log('test2');
}
test3() {setTimeOut(()=> console.log('last'),0);
  test1();
  test2();
  console.log('test3 end');
}
test3();

执行这个脚本会失去如下后果:

test1
test2
test3 end
last

执行过程如下:
1. 执行 test3() 并入栈

|__test3__|

2. 执行 setTimeOut 并入队列

栈:
|__setTimeOut(xxx)__|
|_____test3_________|
队列:
| console.log(‘last’) |

3.test1() 入栈并执行

|__console.log(“test1”)__|
|______test1___________|
|______test3___________|

test1 执行完之后退栈

4.test2() 入栈并执行

|__console.log(“test2”)__|
|______test2___________|
|______test3___________|

test2 执行完之后退栈

5. 继续执行 test3

|__console.log(“test3 end”)__|
|__________test3___________|

test3 执行完之后退栈

6. 栈空之后执行音讯队列内容

队列:
| console.log(‘last’) |

这个线程会先去执行调用栈,调用栈空之后心才会去执行音讯队列中的内容。

4.ES6 工作队列

ECMAScript 2015 / ES6 引进的工作队列的概念,这个工作队列会将 promise 放进去。
音讯队列和工作队列之间的关系能够用在游乐园坐过山车来比喻:
音讯队列把你放在队列的前面,在所有其他人的前面,你必须在那里期待轮到你,而工作队列是疾速通行证 这样您就能够在实现上一次骑行后立刻进行另一次骑行。

例子:

test1() {console.log('test1');
}
test2() {console.log('test2');
}
test3() {setTimeOut(()=> console.log('last'),0);
  new Promise((resolve,reject)=>{resole('before last');
  }).then(res => console.log(res));
  test1();
  test2();
  console.log('test3 end');
}
test3();

执行这个脚本会失去如下后果:

test1
test2
test3 end
before last
last

执行过程如下:
1. 执行 test3() 并入栈

|__test3__|

2. 执行 setTimeOut 并入音讯队列

栈:
|__setTimeOut(xxx)__|
|_____test3_________|
音讯队列:
| console.log(‘last’) |

3. 执行 promise 并入工作队列

栈:
|__resole(xxx)_______|
|_____test3_________|
工作列:
| console.log(‘before last’) |

4.test1() 入栈并执行

|__console.log(“test1”)__|
|______test1___________|
|______test3___________|

test1 执行完之后退栈

5.test2() 入栈并执行

|__console.log(“test2”)__|
|______test2___________|
|______test3___________|

test2 执行完之后退栈

6. 继续执行 test3

|__console.log(“test3 end”)__|
|__________test3___________|

test3 执行完之后退栈

7. 栈空之后执行音讯队列内容

队列:
| console.log(‘last’) |

8. 栈空之后执行工作队列内容

队列:
| console.log(‘before last’) |

退出移动版