先给出一个案例
console.log('1')
let promise = new Promise(function (resolve,reject) {
console.log('2')
resolve(3)
}).then(function (data) {
console.log(data)
})
setTimeout(function () {
console.log('4')
})
console.log('5')
//1,2,5,3,4
new promise()是同步的(执行器函数,同步执行),Promise.then()是微任务,DOM,ajax,setTimeou是宏任务。
内存机制:
js有自动垃圾回收机制,对于基本数据类型,定义一个变量,系统自动分配存储空间。你可以直接操作保存在栈内存空间的值。因此基本数据类型都是按值访问
const a =1
栈内存(先进后出)一般存储基本数据类型和函数:
Number String Null Undefined Boolean
js的引用数据类型值是不固定的:
JavaScript不允许直接访问堆内存中的位置,因此不能直接操作对象的堆内存(先进先出)空间。我们首先是从栈中获取了该对象的地址引用(或者地址指针)。再从堆内存中取得我们需要的数据
事件循环机制:
案例解析:
console.log('script start');
setTimeout(function() {
console.log('timeout1');
}, 10);
new Promise(resolve => {
console.log('promise1');
resolve();
setTimeout(() => console.log('timeout2'), 10);
}).then(function() {
console.log('then1')
})
console.log('script end');
首先,事件循环从宏任务 (macrotask) 队列开始,最初始,宏任务队列中,只有一个 scrip t(整体代码)任务;当遇到任务源 (task source) 时,则会先分发任务到对应的任务队列中去。所以,就和上面例子类似,首先遇到了console.log,输出 script start; 接着往下走,遇到 setTimeout 任务源,将其分发到任务队列中去,记为 timeout1; 接着遇到 promise,new promise 中的代码立即执行,输出 promise1, 然后执行 resolve ,遇到 setTimeout ,将其分发到任务队列中去,记为 timemout2, 将其 then 分发到微任务队列中去,记为 then1; 接着遇到 console.log 代码,直接输出 script end 接着检查微任务队列,发现有个 then1 微任务,执行,输出then1 再检查微任务队列,发现已经清空,则开始检查宏任务队列,执行 timeout1,输出 timeout1; 接着执行 timeout2,输出 timeout2 至此,所有的都队列都已清空,执行完毕。其输出的顺序依次是:script start, promise1, script end, then1, timeout1, timeout2
深入理解JavaScript事件循环机制 - ChessZhang - 博客园
总结:
- 栈:
- 存储基础数据类型
- 按值访问
- 存储的值大小固定
- 由系统自动分配内存空间
- 空间小,运行效率高
- 先进后出,后进先出
- 栈中的DOM,ajax,setTimeout会依次进入到队列中,当栈中代码执行完毕后,再将队列中的事件放到执行栈中依次执行。
- 微任务和宏任务
- 堆:
- 存储引用数据类型
- 按引用访问
- 存储的值大小不定,可动态调整
- 主要用来存放对象
- 空间大,但是运行效率相对较低
- 无序存储,可根据引用直接获取