setTimeout 实现原理, 机制

JS 执行机制说起

浏览器(或者说 JS 引擎)执行 JS 的机制是基于事件循环。

由于 JS 是单线程,所以同一时间只能执行一个任务,其他任务就得排队,后续任务必须等到前一个任务结束才能开始执行。

为了避免因为某些长时间任务造成的无意义等待,JS 引入了异步的概念,用另一个线程来管理异步任务。

同步任务直接在主线程队列中顺序执行,而异步任务会进入另一个任务队列,不会阻塞主线程;

等到主线程队列空了(执行完了)的时候,就会去异步队列查询是否有可执行的异步任务了(异步任务通常进入异步队列之后还要等一些条件才能执行,如 ajax 请求、文件读写),如果某个异步任务可以执行了便加入主线程队列,以此循环;

定时器也是一种异步任务,通常浏览器都有一个独立的定时器模块,定时器的延迟时间就由定时器模块来管理,当某个定时器到了可执行状态,就会被加入主线程队列。

setTimeout 注册的函数 fn 会交给浏览器的定时器模块来管理,延迟时间到了就将 fn 加入主进程执行队列,如果队列前面还有没有执行完的代码,则又需要花一点时间等待才能执行到 fn,所以实际的延迟时间会比设置的长;

如在 fn 之前正好有一个超级大循环,那延迟时间就不是一丁点了。



(function testSetTimeout() {
const label = 'setTimeout';
console.time(label);
setTimeout(() => {
console.timeEnd(label);
}, 0);
for(let i = 0; i < 1000; i++) {
console.log(i);
}
})(); // setTimeout: 133.2880859375ms

setInterval 的实现机制跟 setTimeout 类似,只不过 setInterval 是重复执行的。

对于 setInterval(fn, 100) 容易产生一个误区:

并不是上一次 fn 执行完了之后再过 100ms 才开始执行下一次 fn。 事实上,setInterval 并不管上一次 fn 的执行结果,而是每隔 100ms 就将 fn 放入主线程队列;

而两次 fn 之间具体间隔多久就不一定了,跟 setTimeout 实际延迟时间类似,和 JS 执行情况有关。



(function testSetInterval() {
let i = 0;
const start = Date.now();
const timer = setInterval(() => {
i += 1;
i === 5 && clearInterval(timer);
console.log(`第${i}次开始`, Date.now() - start);
for(let i = 0; i < 10000; i++) {}
console.log(`第${i}次结束`, Date.now() - start);
}, 100);
})();

  1. Stack 栈
  2. Queue 队列
  3. Heap 堆

http://www.alloyteam.com/2016/05/javascript-timer/

requestAnimationFrame

window.requestAnimationFrame(callback);

https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame

// animation

var start = null;
var element = document.getElementById('SomeElementYouWantToAnimate'); function step(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
element.style.transform = 'translateX(' + Math.min(progress / 10, 200) + 'px)';
if (progress < 2000) {
window.requestAnimationFrame(step);
}
} window.requestAnimationFrame(step);

https://caniuse.com/#feat=requestanimationframe

https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/dev-guides/hh920765(v=vs.85)

https://css-tricks.com/using-requestanimationframe/


function repeatOften() {
// Do whatever
requestAnimationFrame(repeatOften);
}
requestAnimationFrame(repeatOften);

requestAnimationFrame demos

https://codepen.io/xgqfrms/pen/ZEzeaEL

https://codepen.io/xgqfrms/pen/zYOZPYd


(function testRequestAnimationFrame() {
window.count = window.count || 0;
window.count++;
if(count < 100) {
const label = 'requestAnimationFrame';
console.time(label);
requestAnimationFrame(() => {
console.timeEnd(label);
testRequestAnimationFrame()
});
}
})();

setImmediate (IE / Edge)

do not use it!

https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate

next.tick()

https://stackoverflow.com/questions/15349733/setimmediate-vs-nexttick

  1. 如果要将函数排在事件队列中已有的任何I / O事件回调之后,请使用setImmediate;

  2. 使用process.nextTick有效地将函数排在事件队列头部,以便在当前函数完成后立即执行;


https://www.haorooms.com/post/js_setTimeout

setTimeout和setinterval的最主要区别是:

  1. setTimeou t只运行一次,也就是说设定的时间到后就触发运行指定代码,运行完后即结束;

    如果运行的代码中再次运行同样的setTimeout命令,则可循环运行。(即 要循环运行,需函数自身再次调用 setTimeout())

  2. setinterval是循环运行的,即每到设定时间间隔就触发指定代码; 这是真正的定时器。

setinterval使用简单,而setTimeout则比较灵活,可以随时退出循环,而且可以设置为按不固定的时间间隔来运行,比如第一次1秒,第二次2秒,第三次3秒。

事件循环模型

在单线程的 Javascript 引擎中,setTimeout() 是如何运行的呢,这里就要提到浏览器内核中的事件循环模型了;

简单的讲,在 Javascript 执行引擎之外,有一个任务队列,当在代码中调用 setTimeout() 方法时,注册的延时方法会交由浏览器内核其他模块(以 webkit 为例,是 webcore 模块)处理,当延时方法到达触发条件,即到达设置的延时时间时,这一延时方法被添加至任务队列里;

这一过程由浏览器内核其他模块处理,与执行引擎主线程独立,执行引擎在主线程方法执行完毕,到达空闲状态时,会从任务队列中顺序获取任务来执行;

这一过程是一个不断循环的过程,称为事件循环模型。

Javascript 执行引擎的主线程运行的时候,产生堆(heap)和栈(stack);

程序中代码依次进入栈中等待执行,当调用 setTimeout() 方法时,即图中右侧 WebAPIs 方法时,浏览器内核相应模块开始延时方法的处理,

当延时方法到达触发条件时,方法被添加到用于回调的任务队列,只要执行引擎栈中的代码执行完毕,主线程就会去读取任务队列,依次执行那些满足触发条件的回调函数。

http://www.alloyteam.com/2015/10/turning-to-javascript-series-from-settimeout-said-the-event-loop-model/

https://www.ruanyifeng.com/blog/2014/10/event-loop.html



xgqfrms 2012-2020

www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!


setTimeout 实现原理, 机制的更多相关文章

  1. Javascript引擎的单线程机制和setTimeout执行原理阐述

    工作中使用setTimeout解决了一个问题,于是对setTimeout的相关资料整理了下,以及对js引擎执行的原理一并整理了下,希望能给码农们一些帮助.若发现有错的地方大家及时指出,共同学习进步. ...

  2. Java提高篇——JVM加载class文件的原理机制

    在面试java工程师的时候,这道题经常被问到,故需特别注意. 1.JVM 简介 JVM 是我们Javaer 的最基本功底了,刚开始学Java 的时候,一般都是从“Hello World ”开始的,然后 ...

  3. JVM加载class文件的原理机制

    Java中的所有类,都需要由类加载器装载到JVM中才能运行.类加载器本身也是一个类,而它的工作就是把class文件从硬盘读取到内存中.在写程序的时候,我们几乎不需要关心类的加载,因为这些都是隐式装载的 ...

  4. 王家林的“云计算分布式大数据Hadoop实战高手之路---从零开始”的第十一讲Hadoop图文训练课程:MapReduce的原理机制和流程图剖析

    这一讲我们主要剖析MapReduce的原理机制和流程. “云计算分布式大数据Hadoop实战高手之路”之完整发布目录 云计算分布式大数据实战技术Hadoop交流群:312494188,每天都会在群中发 ...

  5. Glibc堆块的向前向后合并与unlink原理机制探究

    i春秋作家:Bug制造机 原文来自:Glibc堆块的向前向后合并与unlink原理机制探究 玩pwn有一段时间了,最近有点生疏了,调起来都不顺手了,所以读读malloc源码回炉一点一点总结反思下. U ...

  6. 研究一下Spark Hash Shuffle 和 SortShuffle 原理机制

    研究一下Spark Hash Shuffle 和 SortShuffle 原理机制研究一下Spark Hash Shuffle 和 SortShuffle 原理机制研究一下Spark Hash Shu ...

  7. JVM加载class文件的原理机制(转)

    JVM加载class文件的原理机制 1.Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中 2.java中的 ...

  8. java类什么时候加载?,加载类的原理机制是怎么样的?

    java类什么时候加载?,加载原理机制是怎么样的?   答: 很多人都不是很清楚java的class类什么时候加载在运行内存中,其实类加载的时间是发生在一下几种情况: 1.实例化对象时,就像sprin ...

  9. Java加载Class文件的原理机制

    详见:http://blog.sina.com.cn/s/blog_6cbfd2170100ljmp.html 1.Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器 ...

随机推荐

  1. Angular入门到精通系列教程(14)- Angular 编译打包 & Docker发布

    目录 1. 概要 2. 编译打包 2.1. 基本打包命令 2.2. 打包部署到二级目录 3. Angular站点的发布 3.1. web服务器发布 3.2. 使用docker发布 4. 总结 环境: ...

  2. QR Code Error Correction

    QR Code Error Correction - QRStuff.com https://blog.qrstuff.com/2011/12/14/qr-code-error-correction ...

  3. 使用“2”个参数调用“SetData”时发生异常:“程序集“

    使用"2"个参数调用"SetData"时发生异常:"程序集"Microsoft.VisualStudio.ProjectSystem.VS. ...

  4. 本地MarkDown优雅发表

    本地MarkDown优雅发表 前言 身为一名程序员,记录笔记.发表博客首选便是MarkDown,现在网上有好多发表博客的地方:CSDN.博客园.简书,甚至一些大佬都有自己专属博客,但自己最喜欢的还是博 ...

  5. 20200927gryz校赛心得

    今天gyh学长给我们办了一场校内模拟赛,特地跑来记录一下心得 昨天晚上问了一下lkp学长,听说题目不卡常,不毒瘤,因此我在考试前20分钟仍在若无其事的练习着刚学的强连通分量,丝毫不慌 结果虽然rank ...

  6. HDU1823 Luck ans Love 二维线段树

    Luck and Love HDU - 1823 世界上上最远的距离不是相隔天涯海角 而是我在你面前 可你却不知道我爱你                 ―― 张小娴 前段日子,枫冰叶子给Wiskey ...

  7. MarkDown学习笔记 Typora

    快捷方式篇 新建 ctrl + N 新建窗口 ctrl + shift + N 打开md文件 ctrl + O 快速打开 ctrl + P 保存 ctrl + S 另存为 ctrl + shift + ...

  8. SpringBoot-文件系统-Excel,PDF,XML,CSV

    SpringBoot-文件系统-Excel,PDF,XML,CSV 1.Excel文件管理 1.1 POI依赖 1.2 文件读取 1.3 文件创建 1.4 文件导出 1.5 文件导出接口 2.PDF文 ...

  9. 给jekyll博客添加天气插件

    layout: post title: 给博客添加天气插件 date: 2020-04-26 author: Dapenson header-img: img/post-bg-debug.png ca ...

  10. E 快速排序

    :以下代码可以从数组a[]中找出第k小的元素. 它使用了类似快速排序中的分治算法,期望时间复杂度是O(N)的. 请仔细阅读分析源码,填写划线部分缺失的内容. #include <stdio.h& ...