-
Notifications
You must be signed in to change notification settings - Fork 83
Open
Labels
Description
先看一个题目
function fn(n){
fn(n);
}
fn(1);这个题目的运行结果毫无疑问, 内存溢出, Maximum call stack size exceeded
如果稍微变一下呢?
function fn(n){
setTimeout(()=>fn(n),0)
}
fn(1);这个改变,会发生什么呢?这时候不会内存溢出了。
以上题目能解释明白的,应该很懂异步
简单说,js异步其实是宿主环境赋予给js的一种能力。采用 Event loop的形式去 callback queue(回调队列)取异步任务到 call stack中执行。
看以下图,这个需要理解了就ok了。
js是单线程的,浏览器为那些异步任务单独开辟了一些线程(比如http请求线程,浏览器定时触发器,浏览器事件触发线程),当然我们可以统称为 webAPIs。
因为异步的情况会很多,所以会放到一个叫 callback queue 队列里面(可以叫异步任务队列)。
堆(heap)和栈(stack)共同组成了js主线程,函数的执行就是通过进栈和出栈实现的。
比如图中有一个fn()函数,主线程把它推入栈中,在执行函数体时,发现还需要执行上面的那几个函数,所以又把这几个函数推入栈中,等到函数执行完,就让函数出栈。等到stack清空时,说明一个任务已经执行完了,这时就会从callback queue中寻找下一个人任务推入栈中(这个寻找的过程,叫做event loop,因为它总是循环的查找任务队列里是否还有任务)
- 比如现在有这么一个程序:
setTimeout(fn1, 0)请问fn1会不会立刻执行,答案是不一定。需要看下主线程内是否执行完毕了。如果有程序会先执行
比如:
setTimeout(function(){console.log(1);},0);
console.log(2);会先输出2,然后1
- 回到最开始题目
你知道为何加上定时器,就不会内存溢出了么?因为压根不在js主线程内,所以每次都是避开避开。
