function interval(callback, delay) {
let timeId = setInterval(() => {
callback(timeId) // 通过异步的形式 将timeId 传递出去
}, delay)
}
interval(timeId => {
const div = document.querySelector(‘div’)
let left = div.offsetLeft
div.style.left = left + 10 + ‘px’
console.log(‘left’, left)
if (left + div.offsetWidth >= document.body.clientWidth) {
clearInterval(timeId)
interval(timeId => {
let width = div.offsetWidth
div.style.width = width - 10 + ‘px’
if (width <= 20) {
clearInterval(timeId)
}
}, 100)
}
}, 50)
/*
这里写的延迟执行时长是50ms 但是实际并不是一定是50ms 这个也是个不确定的因素,会等主线程执行结束了之后,
并且任务队列循环到这个任务之后,等待50ms才执行
如此例,必须主线程for循环执行结束了之后才会执行异步任务队列的任务,而主线程可能就会执行好久
*/
for (let i = 0; i < 20000000; i++) {
console.log(i)
}
复习 DOM:
-
DOM.offsetLeft
DOM.offsetWidth
都是属性,获取一个 DOM 元素的 left 属性值和宽度 -
document.body.clientWidth
获取浏览器窗口的宽度
注意点(重点):
- 定时器上规定的时间并不代表一定过这么久就会执行,还要看主线程代码执行的时间和轮询队列的排列
回调地狱的产生
在 JS 中,主线程是从上到下执行的,遇到加载的时候会交给异步加载模块去进行加载,而异步加载模块就没有说先进先出,后进后出的原则的,它的原则就是谁快,就先出谁。
function aMode() {
console.log(‘a模块’)
}
function bMode() {
aMode()
console.log(‘bMode 执行了’)
}
function load(src, reslove, reject) {
let script = document.createElement(‘script’)
script.src = src
script.onload = reslove
script.onerror = reject
document.body.appendChild(script)
}
load(
‘./module/a.js’,
() => {
aMode()
},
() => {
console.log(‘线程加载失败’)
}
)
load(‘./module/b.js’, () => {
bMode()
})
load(‘./’)
console.log(‘主线程’)
很明显,模块 b 是依赖与模块 a 执行的,因为执行模块 b 的时候,会执行模块 a 的aMode()
方法,而再看我们主逻辑代码这,虽然我们代码的顺序是先写了加载 a 模块,再加载 b 模块,但是由于异步加载模块的执行顺序并不是先看到谁执行谁,而是谁先执行完就先出谁,所以以上的代码有一定的几率会报错,如图
- 错误加载时
- 正确加载时
所以,为了解决这个加载快慢的因素,我们就只能等一个模块加载完成之后再去加载第二个模块,就是这样,要实现这个就只能在加载成功的回调函数里面去加载其他的模块,这样就能够保证第一个被依赖的模块一定是已经加载完成的
load(‘./module/a.