<template>
<div>
<div ref="test">{{test}}</div>
<button @click="handleClick">tet</button>
</div>
</template>
export default {
data () {
return {
test: 'begin'
};
},
methods () {
handleClick () {
this.test = 'end';
console.log(this.$refs.test.innerText);//打印“begin”
}
}
}
update () {
/* istanbul ignore else */
if (this.lazy) {
this.dirty = true
} else if (this.sync) {
/*同步则执行run直接渲染视图*/
this.run()
} else {
/*异步推送到观察者队列中,下一个tick时调用。*/
queueWatcher(this)
}
}
/*将一个观察者对象push进观察者队列,在队列中已经存在相同的id则该观察者对象将被跳过,除非它是在队列被刷新时推送*/
export function queueWatcher (watcher: Watcher) {
/*获取watcher的id*/
const id = watcher.id
/*检验id是否存在,已经存在则直接跳过,不存在则标记哈希表has,用于下次检验*/
if (has[id] == null) {
has[id] = true
if (!flushing) {
/*如果没有flush掉,直接push到队列中即可*/
queue.push(watcher)
} else {
// if already flushing, splice the watcher based on its id
// if already past its id, it will be run next immediately.
let i = queue.length - 1
while (i >= 0 && queue[i].id > watcher.id) {
i--
}
queue.splice(Math.max(i, index) + 1, 0, watcher)
}
// queue the flush
if (!waiting) {
waiting = true
nextTick(flushSchedulerQueue)
}
}
}
/**
* Defer a task to execute it asynchronously.
*/
/*
延迟一个任务使其异步执行,在下一个tick时执行,一个立即执行函数,返回一个function
这个函数的作用是在task或者microtask中推入一个timerFunc,在当前调用栈执行完以后以此执行直到执行到timerFunc
目的是延迟到当前调用栈执行完以后执行
*/
export const nextTick = (function () {
/*存放异步执行的回调*/
const callbacks = []
/*一个标记位,如果已经有timerFunc被推送到任务队列中去则不需要重复推送*/
let pending = false
/*一个函数指针,指向函数将被推送到任务队列中,等到主线程任务执行完时,任务队列中的timerFunc被调用*/
let timerFunc
/*下一个tick时的回调*/
function nextTickHandler () {
/*一个标记位,标记等待状态(即函数已经被推入任务队列或者主线程,已经在等待当前栈执行完毕去执行),这样就不需要在push多个回调到callbacks时将timerFunc多次推入任务队列或者主线程*/
pending = false
/*执行所有callback*/
const copies = callbacks.slice(0)
callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}
// the nextTick behavior leverages the microtask queue, which can be accessed
// via either native Promise.then or MutationObserver.
// MutationObserver has wider support, however it is seriously bugged in
// UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It
// completely stops working after triggering a few times... so, if native
// Promise is available, we will use it:
/* istanbul ignore if */
/*
这里解释一下,一共有Promise、MutationObserver以及setTimeout三种尝试得到timerFunc的方法
优先使用Promise,在Promise不存在的情况下使用MutationObserver,这两个方法都会在microtask中执行,会比setTimeout更早执行,所以优先使用。
如果上述两种方法都不支持的环境则会使用setTimeout,在task尾部推入这个函数,等待调用执行。
*/
if (typeof Promise !== 'undefined' && isNative(Promise)) {
/*使用Promise*/
var p = Promise.resolve()
var logError = err => { console.error(err) }
timerFunc = () => {
p.then(nextTickHandler).catch(logError)
// in problematic UIWebViews, Promise.then doesn't completely break, but
// it can get stuck in a weird state where callbacks are pushed into the
// microtask queue but the queue isn't being flushed, until the browser
// needs to do some other work, e.g. handle a timer. Therefore we can
// "force" the microtask queue to be flushed by adding an empty timer.
if (isIOS) setTimeout(noop)
}
} else if (typeof MutationObserver !== 'undefined' && (
isNative(MutationObserver) ||
// PhantomJS and iOS 7.x
MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
// use MutationObserver where native Promise is not available,
// e.g. PhantomJS IE11, iOS7, Android 4.4
/*新建一个textNode的DOM对象,用MutationObserver绑定该DOM并指定回调函数,在DOM变化的时候则会触发回调,该回调会进入主线程(比任务队列优先执行),即textNode.data = String(counter)时便会触发回调*/
var counter = 1
var observer = new MutationObserver(nextTickHandler)
var textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
characterData: true
})
timerFunc = () => {
counter = (counter + 1) % 2
textNode.data = String(counter)
}
} else {
// fallback to setTimeout
/* istanbul ignore next */
/*使用setTimeout将回调推入任务队列尾部*/
timerFunc = () => {
setTimeout(nextTickHandler, 0)
}
}
/*
推送到队列中下一个tick时执行
cb 回调函数
ctx 上下文
*/
return function queueNextTick (cb?: Function, ctx?: Object) {
let _resolve
/*cb存到callbacks中*/
callbacks.push(() => {
if (cb) {
try {
cb.call(ctx)
} catch (e) {
handleError(e, ctx, 'nextTick')
}
} else if (_resolve) {
_resolve(ctx)
}
})
if (!pending) {
pending = true
timerFunc()
}
if (!cb && typeof Promise !== 'undefined') {
return new Promise((resolve, reject) => {
_resolve = resolve
})
}
}
})()
/*Github:https://github.com/answershuto*/
/**
* Flush both queues and run the watchers.
*/
/*nextTick的回调函数,在下一个tick时flush掉两个队列同时运行watchers*/
function flushSchedulerQueue () {
flushing = true
let watcher, id
// Sort queue before flush.
// This ensures that:
// 1. Components are updated from parent to child. (because parent is always
// created before the child)
// 2. A component's user watchers are run before its render watcher (because
// user watchers are created before the render watcher)
// 3. If a component is destroyed during a parent component's watcher run,
// its watchers can be skipped.
/*
给queue排序,这样做可以保证:
1.组件更新的顺序是从父组件到子组件的顺序,因为父组件总是比子组件先创建。
2.一个组件的user watchers比render watcher先运行,因为user watchers往往比render watcher更早创建
3.如果一个组件在父组件watcher运行期间被销毁,它的watcher执行将被跳过。
*/
queue.sort((a, b) => a.id - b.id)
// do not cache length because more watchers might be pushed
// as we run existing watchers
/*这里不用index = queue.length;index > 0; index--的方式写是因为不要将length进行缓存,因为在执行处理现有watcher对象期间,更多的watcher对象可能会被push进queue*/
for (index = 0; index < queue.length; index++) {
watcher = queue[index]
id = watcher.id
/*将has的标记删除*/
has[id] = null
/*执行watcher*/
watcher.run()
// in dev build, check and stop circular updates.
/*
在测试环境中,检测watch是否在死循环中
比如这样一种情况
watch: {
test () {
this.test++;
}
}
持续执行了一百次watch代表可能存在死循环
*/
if (process.env.NODE_ENV !== 'production' && has[id] != null) {
circular[id] = (circular[id] || 0) + 1
if (circular[id] > MAX_UPDATE_COUNT) {
warn(
'You may have an infinite update loop ' + (
watcher.user
? `in watcher with expression "${watcher.expression}"`
: `in a component render function.`
),
watcher.vm
)
break
}
}
}
// keep copies of post queues before resetting state
/**/
/*得到队列的拷贝*/
const activatedQueue = activatedChildren.slice()
const updatedQueue = queue.slice()
/*重置调度者的状态*/
resetSchedulerState()
// call component updated and activated hooks
/*使子组件状态都改编成active同时调用activated钩子*/
callActivatedHooks(activatedQueue)
/*调用updated钩子*/
callUpdateHooks(updatedQueue)
// devtool hook
/* istanbul ignore if */
if (devtools && config.devtools) {
devtools.emit('flush')
}
}
<template>
<div>
<div>{{test}}</div>
</div>
</template>
export default {
data () {
return {
test: 0
};
},
created () {
for(let i = 0; i < 1000; i++) {
this.test++;
}
}
}
<template>
<div>
<div ref="test">{{test}}</div>
<button @click="handleClick">tet</button>
</div>
</template>
export default {
data () {
return {
test: 'begin'
};
},
methods () {
handleClick () {
this.test = 'end';
this.$nextTick(() => {
console.log(this.$refs.test.innerText);//打印"end"
});
console.log(this.$refs.test.innerText);//打印“begin”
}
}
}
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有