setTimeout是面试常见的考题,一直被虐,可是久病成良医,总结一下我所了解的这两个函数的特性和用法以及常见的地方面试
setTimeout(call,[wait,...args])
在wait
延时以后将call
函数加入执行队列中,IE9+ 的浏览器能够附加其余额外参数做为 call
的参数传递。只执行一次。setTnterval(call,[wait,...args])
,与setTimeout
相比,每间隔wait
以后就将call
加入执行队列setTimeout
和setInterval
的返回值是一个正整数,主要为了清除用的(恕我尚未在其余地方使用过),清除对应的两个函数clearTimeout
和clearInterval
,理论上setTimeout
和setInterval
共用一个计时器池,因此清除函数能够混用,可是为了代码可读仍是作区分。经过在内部封装一个函数,而后在setTimeout
中递归的调用实现,美中不足的是没法中止,也就是定时器id没法获取到。ajax
为何要用setTimeout模拟setInterval?api
每一个setTimeout产生的任务会直接push到任务队列中;而setInterval在每次把任务push到任务队列前,都要进行一下判断(看上次的任务是否仍在队列中)。这样某些间隔会被跳过promise
于是咱们通常用setTimeout模拟setInterval,来规避掉上面的缺点。浏览器
function func1(call, wait) {
var done = function() {
call()
setTimeout(() => {
done()
}, wait)
}
setTimeout(done, wait)
}
func1(() => {
console.log("hello")
}, 1000)
复制代码
所谓闭包就是在函数A返回值是B函数,B函数使用了A函数的内部变量,B函数就造成了闭包,当A函数执行结束以后B函数中使用的A函数变量没有跟着销毁,还存在与内存中供B使用。闭包
常见考题app
可使用let
产生块级做用域来处理异步
for (let i = 1; i <= 10; i++) {
setTimeout(() => {
console.log(i)
}, 1000 * i)
}
复制代码
这个主要是理解程序的执行顺序。程序执行分为宏任务和微任务,setTimeout
和setInterval
产生的是宏任务会在下一次事件循环中执行。函数
setTimeout
等须要外部宿主(主要是浏览器)封装的api执行的任务都会建立一个宏任务,在下一次也买你渲染以后执行。exampleui
console.log(1)
setTimeout(() => {
console.log(2)
}, 1000)
new Promise((resolve, reject) => {
console.log(3)
resolve()
}).then(() => {
console.log(4)
})
console.log(5)
setTimeout(() => {
console.log(6)
})
// 1 3 5 4 6 2
复制代码
setTimeout
交给浏览器计时器线程执行 等待 1秒以后将任务加入宏任务队列promise
建立的时候的回调函数直接执行,打印3,.then
是微任务加入微任务队列setTimeout
可是延时比以前的底,先加入宏任务队列因为setTimeout
中会产生一个宏任务,下一次执行的时候执行栈发生了改变,因此这里的this很容易搞混。
这个理解和函数中的this一致,谁调用是谁。setTimeout返回执行的时候没有对象调用它就是window,因此打印1。用箭头函数能够避免这个问题
var x = 1;
var obj = {
x: 2,
y: function(){
console.log(this.x);
}
};
setTimeout(obj.y,1000); // 1
复制代码
只要是为了屡次渲染页面,可让其余任务穿插在每次也买你渲染之间执行,不至于页面卡顿
要求:动态建立一个表格,一共10000行,每行10个单元格
/** * 常规的 */
var tbody = document.getElementsByTagName('tbody')[0];
var allLines = 10000;
// 每次渲染的行数
console.time('wd');
for(var i=0; i<allLines; i++){
var tr = document.createElement('tr');
for(var j=0; j<10; j++){
var td = document.createElement('td');
td.appendChild(document.createTextNode(i+','+j));
tr.appendChild(td);
}
tbody.appendChild(tr);
}
console.timeEnd('wd'); // 总共耗时180ms, 浏览器已经给出警告![Violation] 'setTimeout' handler took 53ms
/** * setTimeout 切割 */
var tbody = document.getElementsByTagName('tbody')[0];
var allLines = 10000;
// 每次渲染的行数
var everyTimeCreateLines = 80;
// 当前行
var currentLine = 0;
setTimeout(function renderTable(){
console.time('wd');
for(var i=currentLine; i<currentLine+everyTimeCreateLines && i<allLines; i++){
var tr = document.createElement('tr');
for(var j=0; j<10; j++){
var td = document.createElement('td');
td.appendChild(document.createTextNode(i+','+j));
tr.appendChild(td);
}
tbody.appendChild(tr);
}
console.timeEnd('wd');
currentLine = i;
if(currentLine < allLines){
setTimeout(renderTable,0);
}
},0);
// 此次异步按批次建立,没有耗时的警告。由于控制了每次代码在50ms内运行。实际上每80行耗时约10ms左右。这就不会引发页面卡顿等问题。
复制代码