- 浏览器一个瞬间只能有一个线程在执行,很自然地,有一个问题:有长任务怎么办,执行很长时间的一段代码,唯一线程不能做任何其他事情,在100ms内也不会响应用户操作,卡死了。
function abcd(){
console.log('A') // 假定需要 50ms
console.log('B') // 假定需要 50ms
console.log('C') // 假定需要 50ms
console.log('D') // 假定需要 50ms
}
- 现在有一个很自然的想法,就是我能不能把这个长任务分割成多个小任务来执行,执行完了一个小任务之后,把线程让出去,先让别人用,让UI响应用户的操作,用户是爷爷,你先响应用户操作,这样自然就不会卡。 这个时候,你需要知道一个重要的信息:定时器可以让出线程。
function a(){
console.log("A")
}
setTimeout(a,250)
这段code的意思是:在250ms之后向任务队列插入一个执行a function的任务,在这个时间点之前,其他所有UI更新和javascript都可以执行,不影响响应用户操作
- 整理一下我们的想法,可以有:
function a(){
console.log("A")
}
function b(){
console.log("B")
}
function c(){
console.log("C")
}
function d(){
console.log("D")
}
setTimeout(a,250)
setTimeout(b,250*2)
setTimeout(c,250*3)
setTimeout(d,250*4)
整理一下:
setTimeout(function(){
a();
setTimeout(function(){
b()
setTimetout(function(){
c();
setTimetout(function(){
d()
},250)
},250)
},250)
},250)
这样的代码太丑陋了,这个时候,我们需要知道一种【数组模式】,可以更简洁,把所有的任务依次放在一个数组里,依次取出来依次执行
function a(){
console.log("A")
}
function b(){
console.log("B")
}
function c(){
console.log("C")
}
function d(){
console.log("D")
}
const tasks = [a,b,c,d]
function execute(){
let task = tasks.shift();
task();
if(tasks.length>0){
setTimeout(execute,250)
}
}
execute()
把setTimetout替换成requestIdleCallback(facebook有一个更好的实现)
function a(){
console.log("A")
}
function b(){
console.log("B")
}
function c(){
console.log("C")
}
function d(){
console.log("D")
}
const tasks = [a,b,c,d]
function execute(){
let task = tasks.shift();
task();
if(tasks.length>0){
requestIdleCallback(execute)
}
}
execute()
恭喜你,你知道了React Scheduler和React Fiber引入的原理。React Fiber和Scheduler引入的本质原因是分割长任务,按照重要程度依次执行。