1.关于javaScript
在我们所学习的javaScript知识中,javaScript是单线程语言,同时只能执行一项任务。其实javaScript中的多线程是用多线程模拟出来的。
2.关于进程、单线程、多线程
- 进程
当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。而一个进程又是由多个线程所组成的。
- 单线程
线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。
- 多线程
多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。
3.javaScript中的同步和异步
单线程就意味着,所有的任务都需要排队,只有前一个任务执行结束了,才会执行后一个任务。如果前一个任务没有执行结束或遇到一个耗时很长的任务,那么后一个任务就处于一直等待的状态。
于是javaScript语言的设计者意识到了这个问题,于是js将任务分为两种:同步任务与异步任务。
- 同步任务
同步任务就是后一个任务必须等待前一个任务执行完才能执行,是在主线程上执行
- 异步任务
异步任务就是不会直接进去进入主线程执行,而是进入任务队列,只有当任务队列通知异步任务可以执行时,异步任务才会被推入主线程执行。
4.setTimeout和Promise
- 事件循环的顺序,决定js代码的执行顺序。进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务。
- 在js中,异步任务除了有
setTimeout这类的异步任务,还有一类就是es6中很常用promise...then这类的异步任务,因此除了同步任务和异步任务,任务还可以更加细分为macrotask(宏任务)和microtask(微任务) - macrotask: 包括setTimeout、setInterval和执行栈
- microtask: 包括Promise、process.nextTick
// Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。
console.log('enent-loop');//1
// setTimeout()=>{}挂起
// setTimeout1
setTimeout(()=>{//event-loop event-task 任务队列 -> 属于主线程 队列结构 当事件信息
// 当主线程停下来后 轮询 enent-loop task-queue
console.log('setTimeout1');//2
Promise.resolve().then(data=>{//promise
console.log(2222);//3
})
},0)
//setTimeout2
setTimeout(()=>{//宏任务
console.log('setTimeout2');//4
},0)
Promise.resolve().then(data=>{//promise-> 微任务
console.log(1111);//5
})
console.log('enent-loop end');//6
// 运行顺序为1 6 5 2 3 4 每次只做一个任务
分析上面执行过程:
- 第一轮:主线程开始执行,先执行 console.log(),输出
enent-loop。 - 遇到setTimeout记为setTimeout1,将setTimeout的回调函数丢到宏任务队列中。
- 再往下执行遇到setTimeout记为setTimeout2,将setTimeout的回调函数丢到宏任务队列中。
- 再往下继续执行遇到Promise.resolve().then的回调函数丢到微任务队列中。
- 再继续执行console.log(),输出
enent-loop end。 - 再继续执行 Promise.resolve().then,输出
1111。 - 第二轮: 从宏任务队列,发现setTimeout1回调,执行console.log(),输出
setTimeout1。 - 再遇到Promise.resolve().then,输出
2222。 - 再往下执行setTimeout2,输出
setTimeout2。
最后的输出顺序为:
enent-loop
enent-loop end
1111
setTimeout1
2222
setTimeout2
setTimeout
我们知道setTimeout是用于异步延时执行的。下面例子是实现延时2秒执行:
setTimeout(() => {
console.log('延时2秒');
},2000)
console.log
console.log我们经常使用到,但是不知道console.log是同步任务吧!
console.log('同步任务!');
Promise
Promise对象代表了未来将要发生的事件,用来传递异步操作的消息。
let promise = new Promise(function(resolve, reject){
console.log("AAA");
resolve()
});
Promise.resolve().then(data=>{
console.log('BBB');
})
console.log("CCC")
执行后,我们发现输出顺序总是 AAA -> CCC -> BBB。在Promise新建后会立即执行,所以首先输出 AAA。然后,then方法指定的回调函数将在当前脚本所有同步任务执行完后才会执行,所以再执行CCC 再执行then输出BBB 。