首先由一个小题目导入
console.log(1) // 同步任务进入主线程
setTimeout(fun(),0)
// 异步任务,被放入event table, 0秒之后被推入event queue里
console.log(3) // 同步任务进入主线程
为什么setTimeout的延迟时间是0毫秒却在最后执行的???
1、3是同步任务马上会被执行,执行完成之后主线程空闲去event queue(事件队列)里查看是否有任务在等待执行.
node.js 有所体现~~~???
node.js的事件循环(eventloop)是怎么运作的?
- 1、每个Node.js进程只有一个主线程在执行程序代码,形成一个执行栈(execution context stack)。
- 2、主线程之外,还维护了一个"事件队列"(Event queue)。当用户的网络请求或者其它的异步操作到来时,node都会把它放到Event Queue之中,此时并不会立即执行它,代码也不会被阻塞,继续往下走,直到主线程代码执行完毕。
3、主线程代码执行完毕完成后,然后通过Event Loop,也就是事件循环机制,开始到Event Queue的开头取出第一个事件,从线程池中分配一个线程去执行这个事件,接下来继续取出第二个事件,再从线程池中分配一个线程去执行,然后第三个,第四个。主线程不断的检查事件队列中是否有未执行的事件,直到事件队列中所有事件都执行完了,此后每当有新的事件加入到事件队列中,都会通知主线程按顺序取出交EventLoop处理。当有事件执行完毕后,会通知主线程,主线程执行回调,线程归还给线程池。
4、主线程不断重复上面的第三步。
异步函数这么多,处理起来是不是麻烦???这时候有 async await 解决这类问题???
什么是 async 函数
一句话,它就是 Generator 函数的语法糖。
院一峰老师es6文中,
const fs = require('fs');
const readFile = function (fileName) {
return new Promise(function (resolve, reject) {
fs.readFile(fileName, function(error, data) {
if (error) return reject(error);
resolve(data);
});
});
};
const gen = function* () {
const f1 = yield readFile('/etc/fstab');
const f2 = yield readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
上面代码的函数gen可以写成async函数,就是下面这样。
const asyncReadFile = async function () {
const f1 = await readFile('/etc/fstab');
const f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
一比较就会发现,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已.
new Promise(function (resolve) {
console.log('1')// 宏任务一
resolve()
}).then(function () {
console.log('3') // 宏任务一的微任务
})
setTimeout(function () {
// 宏任务二
console.log('4')
setTimeout(function () {
// 宏任务五
console.log('7')
new Promise(function (resolve) {
console.log('8')
resolve()
}).then(function () {
console.log('10')
setTimeout(function () {
// 宏任务七
console.log('12')
})
})
console.log('9')
})
})
setTimeout(function () {
// 宏任务三
console.log('5')
})
setTimeout(function () {
// 宏任务四
console.log('6')
setTimeout(function () {
// 宏任务六
console.log('11')
})
})
console.log('2') // 宏任务一
全部的代码作为第一个宏任务进入主线程执行。
首先输出1,是同步代码。then回调作为微任务进入到宏任务一的微任务队列。
下面最外层的三个setTimeout分别是宏任务二、宏任务三、宏任务四按序排入宏任务队列。
输出2,现在宏任务一的同步代码都执行完成了接下来执行宏任务一的微任务输出3。 第一轮事件循环完成了
现在执行宏任务二输出4,后面的setTimeout作为宏任务五排入宏任务队列。 第二轮事件循环完成了
执行宏任务三输出5,执行宏任务四输出6,宏任务四里面的setTimeout作为宏任务六。
执行宏任务五输出7,8。then回调作为宏任务五的微任务排入宏任务五的微任务队列。
输出同步代码9,宏任务五的同步代码执行完了,现在执行宏任务五的微任务。
输出10,后面的setTimeout作为宏任务七排入宏任务的队列。 宏任务五执行完成了,当前已经是第五轮事件循环了。
执行宏任务六输出11,执行宏任务七输出12。