首先js是一门单线程的语言,但是他却可以处理异步的任务,这就依靠了js的事件循环机制(event loop)
线程
单线程:在一个时间段内依次执行一段任务
a b c d=>a->b->c->d? ?只有执行完a才能执行b,执行完b才能执行c.....?
例子:一盘包子,第一个吃完第二个人才能接着吃,第二个人吃完第三个人接着吃
多线程:在一个时间段内同时执行多段任务
a b c d=>? ?同时在执行abcd? ?
例子:一盘包子,四个人可以同时吃
进程
比如说QQ,我打开一个QQ就启动了一个QQ的进程,但是我可以打开好几个QQ,就相当于开了好几个进程。
事件循环机制
js引擎自顶向下依次执行,它会先执行主线程中(执行栈)中的同步任务,在执行同步任务的过程中,如果遇到异步任务,会将异步任务放到主线程外的任务队列中,待js执行完主线程中的所有同步任务后,此时js引擎空闲,它会去查询任务队列中的异步任务,异步任务分为宏任务与微任务,将异步任务放到主线程中执行,如果异步任务中还包括异步任务,那就继续将异步任务放到任务队列中,等主线程执行完所有任务后再查询任务队列中的异步任务....循环下去
?
理解vue中的$nextTick
$nextTick:在下一次DOM更新循环结束之后执行延迟回调(概念很短,需要理解)
注:先明确Vue中的data是同步的,但是DOM渲染却是异步的。
执行过程:当次的data确定,dom渲染完毕->进行修改data->data发生改变,但是Dom渲染是异步的,此时数据变了但是视图没变。
解决:使用$nextTick,此时会等待第二次DOM渲染完毕后再去执行回调,可以理解成数据变了,视图也变了(dom渲染完了)再执行
场景:我们在开发中会可能会使用轮播图(swiper),如果我们在mounted中创建swiper实例,此时轮播图实例已经创建好了,但是轮播图的数据是异步请求回来的,此时数据还没回来,轮播图失效,所以这个方法显然是不合适的。这个时候我们可以用监视属性(watch)监视轮播图数据的数组,一旦数据返回了,我们就用$nextTick中去创建swiper实例,此时数据也改变了dom也渲染完毕了,我创建的swiper实例自然也有效果了。
场景二:后台管理系统中有个编辑查看模式(edit->view),span标签和input标签的切换,如果用v-if会出现一个bug,当我们想从查看模式进入到编辑模式让input框自动获取焦点,因为v-if之前已经将input框销毁了,当再次显示input框时,dom是未渲染完毕的,此时无法拿到input的标签,因此没法自动获取焦点,故用到$nextTick,待dom渲染完成后,此时可以拿到input节点,故可以通过input的方法实现自动获取焦点。
|