永年做网站多少钱seo外包公司如何优化

当前位置: 首页 > news >正文

永年做网站多少钱,seo外包公司如何优化,网站开发人员绩效考核表,vps docker wordpressnexttick是啥 nextTick是Vue提供的一个全局API#xff0c;由于Vue的异步更新策略导致我们对数据的修改不会更新#xff0c;如果此时想要获取更新后的Dom#xff0c;就需要使用这个方法. vue的异步更新策略意思是如果数据变化,vue不会立刻更新dom,而是开启一个队列,把组件更…nexttick是啥 nextTick是Vue提供的一个全局API由于Vue的异步更新策略导致我们对数据的修改不会更新如果此时想要获取更新后的Dom就需要使用这个方法. vue的异步更新策略意思是如果数据变化,vue不会立刻更新dom,而是开启一个队列,把组件更新函数保存在队列里,在统一事件循环中发生的所有数据变更会异步的批量更新,这一策略导致我们对数据的修改不会立即体现在dom上,此时如果想要获取更新后的dom状态,就要使用nexttick nextTick所指定的回调会在浏览器更新DOM完毕之后再执行。即在一次事件循环中更新了数据把更新Dom的操作放入队列中使用了nextTick则把nextTick里的回调放入队列中执行完所有的同步代码后去执行微任务即依次调用队列里的函数。 函数签名 nextTickT void, R void(this: T, fn?: (this: T) R): PromiseAwaitedR this不是参数是ts中的一个语法给 this 定义类型。给用于绑定回调函数中的 this 上下文可以省略。 fn要异步执行的回调函数是一个函数可以省略。 函数返回一个 PromisePromise 的泛型为 Awaited表示回调函数执行后的返回值。 使用场景: created中想要获取dom时响应式数据变化后获取dom更新后的状态,比如希望获取列表更新后的高度 vm.name changed vm.\(nextTick((){ // 要在更新数据的后面使用console.log(app.innerHTML) })vue2、vue3中nexttick源码 简单来讲就是nexttick回调函数使用promise.then方式放入了异步,在所有dom都更新完成后才调用 先上一个小例子,(来自https://b23.tv/AmCLtgx), async increment() {this.count;//dom还未更新console.log(document.getElementById(counter).textContent)//0await nextTick();//dom已经更新conosle.log(document.getElementById(counter).textContent)//1我们先看,响应式数据count改变之后,会发生什么. (具体代码讲解放在代码注释里了,以下为vue3源码) 让与响应式数据相关连的函数去排队,调用queueJob() 源码位置:(太长了,只放一部分) https://github.com/vuejs/core/blob/main/packages/runtime-core/src/renderer.ts // 为组件创建一个响应式效果以便在组件的依赖项发生变化时触发重新渲染,换句话说,就是一个响应式数据改变后, 与它相关联的函数用什么方式去执行 // create reactive effect for renderingconst effect (instance.effect new ReactiveEffect(componentUpdateFn,//与响应式数据相关联的函数NOOP,//空函数,表示没有特定的调度逻辑() queueJob(update),//响应式数据改变后,不会立刻执行componentUpdateFn,而是让componentUpdateFn去排队,在未来某一时刻执行、instance.scope, // track it in components effect scope))排队函数具体内容 源码位置: https://github.com/vuejs/core/blob/main/packages/runtime-core/src/scheduler.ts queueJob方法: 把上一步中输入的参数update(也就是job)按特定规则推到queue任务队列里, 调用queueFlush() export function queueJob(job: SchedulerJob) {// the dedupe search uses the startIndex argument of Array.includes()// by default the search index includes the current job that is being run// so it cannot recursively trigger itself again.// if the job is a watch() callback, the search will start with a 1 index to// allow it recursively trigger itself - it is the users responsibility to// ensure it doesnt end up in an infinite loop.//先检查queue数组是否为空或者job是否已经包含在queue数组中。这个检查确保相同的job不会被多次排队。if (!queue.length ||!queue.includes(job,isFlushing job.allowRecurse ? flushIndex 1 : flushIndex,)) {if (job.id null) {//如果job无id属性,把job插入到queue数组末尾queue.push(job)} else {//如果job有id属性,就按照id把job插入到queue数组中特定位置queue.splice(findInsertionIndex(job.id), 0, job)}queueFlush()//刷新队列} }queueFlush方法: 把flushJobs(真正刷新队列的函数)放在promise.then里,等同步任务都完成后才真的刷新队列,再执行里面的更新函数 function queueFlush() {//刷新队列方法if (!isFlushing !isFlushPending) {//当前没有正在进行的刷新操作并且没有待处理(被挂起)的刷新操作isFlushPending true//表示有一个刷新操作待处理(被挂起)currentFlushPromise resolvedPromise.then(flushJobs)}//注意这里是promise,属于微任务,所以会在未来某一时刻异步的执行,因此,当flushjob这个方法真正执行时,其实其他所有的同步代码都已经执行完了 }flushjob方法:按特定顺序(从父组件更新到子组件遍历并执行任务队列queue中的任务, 并处理执行过程中的任何错误。 function flushJobs(seen?: CountMap) {//循环遍历所有的组件更新函数,去更新所有的组件isFlushPending falseisFlushing trueif (__DEV__) {seen seen || new Map()}// Sort queue before flush.// This ensures that:// 1. Components are updated from parent to child. (because parent is always// created before the child so its render effect will have smaller// priority number)// 2. If a component is unmounted during a parent components update,// its update can be skipped.queue.sort(comparator)//排序,确保组件从父组件更新到子组件并允许跳过已卸载组件的更新。// conditional usage of checkRecursiveUpdate must be determined out of// try ... catch block since Rollup by default de-optimizes treeshaking// inside try-catch. This can leave all warning code unshaked. Although// they would get eventually shaken by a minifier like terser, some minifiers// would fail to do that (e.g. https://github.com/evanw/esbuild/issues/1610)const check __DEV__? (job: SchedulerJob) checkRecursiveUpdates(seen!, job): NOOPtry {//遍历作业队列。for (flushIndex 0; flushIndex queue.length; flushIndex) {const job queue[flushIndex]if (job job.active ! false) {if (__DEV__ check(job)) {continue}callWithErrorHandling(job, null, ErrorCodes.SCHEDULER)}}} finally {flushIndex 0queue.length 0flushPostFlushCbs(seen)isFlushing falsecurrentFlushPromise null// some postFlushCb queued jobs!// keep flushing until it drains.if (queue.length || pendingPostFlushCbs.length) {//若queue仍然有作业,或有待处理的后续刷新回调,则递归调用flushjob,直到队列为空且所有回调都执行完毕flushJobs(seen)}} }nextTick: 获取queueFlush中用到的resolvedPromise, 用then方法执行nexttick的回调函数, export function nextTickT void, R void(this: T,//确保回调函数fn在执行时具有正确的上下文fn?: (this: T) R, ): PromiseAwaitedR {const p currentFlushPromise || resolvedPromisereturn fn ? p.then(this ? fn.bind(this) : fn) : p }//如果提供了回调函数 fn则在 p 的 promise 对象上调用 then 方法。如果有可用的 this 上下文则使用 bind 方法将 fn 函数绑定到 this 上下文。否则直接使用 fn。 //如果未提供回调函数fn 为假值则直接返回 p 的 promise 对象。回看一开始的例子, async increment() {this.count;//导致组件更新函数入队//dom还未更新console.log(document.getElementById(counter).textContent)//0await nextTick();//导致下面所有代码封装成一个匿名函数,并放到刚才的组件更新函数后面,//因此清空队列的时候,会先把所有的组件全清空后,才会执行nexttick后的延迟的语句或回调函数//dom已经更新conosle.log(document.getElementById(counter).textContent)//1vue2中netxtick源码位置: https://github.com/vuejs/vue/blob/main/src/core/util/next-tick.ts 里面用到了优雅降级,可以看看,不多写了 /* globals MutationObserver */import { noop } from shared/util import { handleError } from ./error import { isIE, isIOS, isNative } from ./envexport let isUsingMicroTask falseconst callbacks: ArrayFunction [] let pending falsefunction flushCallbacks() {pending falseconst copies callbacks.slice(0)callbacks.length 0for (let i 0; i copies.length; i) {copies[i]()} }// Here we have async deferring wrappers using microtasks. // In 2.5 we used (macro) tasks (in combination with microtasks). // However, it has subtle problems when state is changed right before repaint // (e.g. #6813, out-in transitions). // Also, using (macro) tasks in event handler would cause some weird behaviors // that cannot be circumvented (e.g. #7109, #7153, #7546, #7834, #8109). // So we now use microtasks everywhere, again. // A major drawback of this tradeoff is that there are some scenarios // where microtasks have too high a priority and fire in between supposedly // sequential events (e.g. #4521, #6690, which have workarounds) // or even between bubbling of the same event (#6566). let timerFunc //优雅降级 // 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 next, \)flow-disable-line / if (typeof Promise ! undefined isNative(Promise)) {//首先,判断是否原生支持Promiseconst p Promise.resolve()timerFunc () {p.then(flushCallbacks)// In problematic UIWebViews, Promise.then doesnt completely break, but// it can get stuck in a weird state where callbacks are pushed into the// microtask queue but the queue isnt 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)}isUsingMicroTask true } else if (//其次 判断是否原生支持MutationObserver!isIE typeof MutationObserver ! undefined (isNative(MutationObserver) ||// PhantomJS and iOS 7.xMutationObserver.toString() [object MutationObserverConstructor]) ) {// Use MutationObserver where native Promise is not available,// e.g. PhantomJS, iOS7, Android 4.4// (#6466 MutationObserver is unreliable in IE11)let counter 1const observer new MutationObserver(flushCallbacks)const textNode document.createTextNode(String(counter))observer.observe(textNode, {characterData: true})timerFunc () {counter (counter 1) % 2textNode.data String(counter)}isUsingMicroTask true } else if (typeof setImmediate ! undefined isNative(setImmediate)) {// 再次 判断是否原生支持setImmediate // Fallback to setImmediate.// Technically it leverages the (macro) task queue,// but it is still a better choice than setTimeout.timerFunc () {setImmediate(flushCallbacks)} } else {// 最后 都不支持的情况下 则使用setTimeout来兜底// Fallback to setTimeout.timerFunc () {setTimeout(flushCallbacks, 0)} }// 将回调函数cb包装成一个箭头函数push到事件队列callbacks中 export function nextTick(): Promisevoid export function nextTickT(this: T, cb: (this: T, …args: any[]) any): void export function nextTickT(cb: (this: T, …args: any[]) any, ctx: T): void /** internal*/ export function nextTick(cb?: (…args: any[]) any, ctx?: object) {let _resolvecallbacks.push(() {if (cb) {try {cb.call(ctx)} catch (e: any) {handleError(e, ctx, nextTick)}} else if (_resolve) {_resolve(ctx)}})if (!pending) {pending truetimerFunc()}// $flow-disable-lineif (!cb typeof Promise ! undefined) {return new Promise(resolve {_resolve resolve})} }