We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
js的任务分为 同步 和 异步 两种,它们的处理方式也不同,同步任务是直接在主线程上排队执行,异步任务则会被放到任务队列中,若有多个任务(异步任务)则要在任务队列中排队等待,任务队列类似一个缓冲区,任务下一步会被移到调用栈(call stack),然后主线程执行调用栈的任务。
单线程是指js引擎中负责解析执行js代码的线程只有一个(主线程),即每次只能做一件事,而我们知道一个ajax请求,主线程在等待它响应的同时是会去做其它事的,浏览器先在事件表注册ajax的回调函数,响应回来后回调函数被添加到任务队列中等待执行,不会造成线程阻塞,所以说js处理ajax请求的方式是异步的。
总而言之,检查调用栈是否为空,以及确定把哪个task加入调用栈的这个过程就是事件循环,而js实现异步的核心就是事件循环。
包含执行整体的js代码,事件回调,XHR回调,定时器(setTimeout/setInterval/setImmediate),IO操作,UI render
更新应用程序状态的任务,包括promise回调,MutationObserver,process.nextTick,Object.observe 其中setImmediate和process.nextTick是nodejs的实现。
大致如下图所示:
总结起来,一次事件循环的步骤包括:
这里需要注意,由于整体script就是一个宏任务,所以一开始在主线程执行完后,一定是去执行一次微任务,如下面的执行顺序一样。
记住: 事件循环从宏任务 (macrotask) 队列开始,最初始,宏任务队列中,只有一个 scrip t(整体代码)任务;当遇到任务源 (task source) 时,则会先分发任务到对应的任务队列中去。
mactotask & microtask的执行顺序
console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0); Promise.resolve().then(function() { console.log('promise1'); }).then(function() { console.log('promise2'); }); console.log('script end');
这是常见的同步与异步的逻辑,那么就有一个逻辑的执行先后问题。可以想想上面的执行结果会是怎样呢?
所有的任务可以分为同步任务和异步任务,同步任务一般会直接进入到主线程中执行;而异步任务会通过任务队列( Event Queue )的机制来进行协调。
具体的可以用下面的图来大致说明一下:
同步和异步任务分别进入不同的执行环境,同步的进入主线程,即主执行栈,异步的进入 Event Queue 。主线程内的任务执行完毕为空,会去 Event Queue 读取对应的任务,推入主线程执行。 上述过程的不断重复就是我们说的 Event Loop (事件循环)。
所以可以看到上面首先会输出: 'script start'、script end',即一定是主线程的同步任务全部执行完后才会去执行异步任务。
现在来分析下上面代码的执行流程:
特别注意一下示例情况:
setTimeout(function() {console.log('timer1')}, 0) setTimeout(function() {console.log('timer2')}, 0) new Promise(function executor(resolve) { console.log('promise 1') setTimeout(() => { resolve(); }, 50) // 这里的延时会使得then回调在setTimeout之后执行,因为延迟时间比所有setTimeout都长。 console.log('promise 2') }).then(function() { console.log('promise then') }) console.log('end')
运行结果如下:
new Promise 中的代码无论是否在 resolve()前还是后,都会立即执行,只是then回调才会被推到微任务队列中。
javascript运行时,一方面引用引擎自身提供的api进行解析,一方面使用浏览器提供的web api(DOM、AJAX、setTimeout等)进行工作.
JavaScript是一种单线程编程语言,这意味着它只有一个调用堆栈。因此,它一次只能做一件事。
调用栈是一种数据结构,它记录了我们在程序中的位置。如果我们运行到一个函数,它就会将其放置到栈顶,当从这个函数返回的时候,就会将这个函数从栈顶弹出,这就是调用栈做的事情。
"堆栈溢出",当你达到调用栈最大的大小的时候就会发生这种情况,而且这相当容易发生,特别是在你写递归的时候却没有全方位的测试它。
深入理解JavaScript事件循环机制 深入理解js事件循环机制(浏览器篇) JavaScript 运行机制详解:再谈Event Loop
The text was updated successfully, but these errors were encountered:
No branches or pull requests
单线程和异步
js的任务分为 同步 和 异步 两种,它们的处理方式也不同,同步任务是直接在主线程上排队执行,异步任务则会被放到任务队列中,若有多个任务(异步任务)则要在任务队列中排队等待,任务队列类似一个缓冲区,任务下一步会被移到调用栈(call stack),然后主线程执行调用栈的任务。
单线程是指js引擎中负责解析执行js代码的线程只有一个(主线程),即每次只能做一件事,而我们知道一个ajax请求,主线程在等待它响应的同时是会去做其它事的,浏览器先在事件表注册ajax的回调函数,响应回来后回调函数被添加到任务队列中等待执行,不会造成线程阻塞,所以说js处理ajax请求的方式是异步的。
总而言之,检查调用栈是否为空,以及确定把哪个task加入调用栈的这个过程就是事件循环,而js实现异步的核心就是事件循环。
macrotask & microtask
macrotask
包含执行整体的js代码,事件回调,XHR回调,定时器(setTimeout/setInterval/setImmediate),IO操作,UI render
microtask
更新应用程序状态的任务,包括promise回调,MutationObserver,process.nextTick,Object.observe
其中setImmediate和process.nextTick是nodejs的实现。
事件处理过程
大致如下图所示:
总结起来,一次事件循环的步骤包括:
这里需要注意,由于整体script就是一个宏任务,所以一开始在主线程执行完后,一定是去执行一次微任务,如下面的执行顺序一样。
mactotask & microtask的执行顺序
由一个例子开始
这是常见的同步与异步的逻辑,那么就有一个逻辑的执行先后问题。可以想想上面的执行结果会是怎样呢?
任务队列
所有的任务可以分为同步任务和异步任务,同步任务一般会直接进入到主线程中执行;而异步任务会通过任务队列( Event Queue )的机制来进行协调。
具体的可以用下面的图来大致说明一下:
同步和异步任务分别进入不同的执行环境,同步的进入主线程,即主执行栈,异步的进入 Event Queue 。主线程内的任务执行完毕为空,会去 Event Queue 读取对应的任务,推入主线程执行。 上述过程的不断重复就是我们说的 Event Loop (事件循环)。
所以可以看到上面首先会输出: 'script start'、script end',即一定是主线程的同步任务全部执行完后才会去执行异步任务。
现在来分析下上面代码的执行流程:
特别注意一下示例情况:
运行结果如下:
new Promise 中的代码无论是否在 resolve()前还是后,都会立即执行,只是then回调才会被推到微任务队列中。
额外知识点集
V8引擎
Runtime(运行时)
javascript运行时,一方面引用引擎自身提供的api进行解析,一方面使用浏览器提供的web api(DOM、AJAX、setTimeout等)进行工作.
调用栈
JavaScript是一种单线程编程语言,这意味着它只有一个调用堆栈。因此,它一次只能做一件事。
调用栈是一种数据结构,它记录了我们在程序中的位置。如果我们运行到一个函数,它就会将其放置到栈顶,当从这个函数返回的时候,就会将这个函数从栈顶弹出,这就是调用栈做的事情。
"堆栈溢出",当你达到调用栈最大的大小的时候就会发生这种情况,而且这相当容易发生,特别是在你写递归的时候却没有全方位的测试它。
参考
深入理解JavaScript事件循环机制
深入理解js事件循环机制(浏览器篇)
JavaScript 运行机制详解:再谈Event Loop
The text was updated successfully, but these errors were encountered: