이 글의 내용은 Vue의 가상 돔 비교 원리에 대한 소개입니다(예제 설명). 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.
먼저 가상 DOM 비교 단계가 있는 이유에 대해 이야기해 보겠습니다. Vue는 데이터 중심 뷰(데이터 변경으로 인해 뷰 변경이 발생함)라는 것을 알고 있지만 특정 데이터가 변경되면 뷰가 변경된다는 것을 알게 됩니다. 전체 뷰가 아닌 로컬로 새로 고쳐집니다. 데이터에 해당하는 뷰를 정확하게 찾고 다시 렌더링할 때 업데이트하는 방법은 무엇입니까? 그런 다음 데이터 변경 전후의 DOM 구조를 가져와 차이점을 찾아 업데이트해야 합니다!
가상 DOM은 본질적으로 실제 DOM에서 추출된 단순 객체입니다. 단순한 p에 200개 이상의 속성이 포함되어 있지만 실제로 필요한 것은 tagName
뿐이므로 실제 DOM에 대한 직접 작업은 성능에 큰 영향을 미칩니다! tagName
,所以对真实dom直接操作将大大影响性能!
简化后的虚拟节点(vnode)大致包含以下属性:
{ tag: 'p', // 标签名 data: {}, // 属性数据,包括class、style、event、props、attrs等 children: [], // 子节点数组,也是vnode结构 text: undefined, // 文本 elm: undefined, // 真实dom key: undefined // 节点标识 }
虚拟dom的比较,就是找出新节点(vnode)和旧节点(oldVnode)之间的差异,然后对差异进行打补丁(patch)。大致流程如下
整个过程还是比较简单的,新旧节点如果不相似,直接根据新节点创建dom;如果相似,先是对data比较,包括class、style、event、props、attrs等,有不同就调用对应的update函数,然后是对子节点的比较,子节点的比较用到了diff算法,这应该是这篇文章的重点和难点吧。
值得注意的是,在Children Compare
过程中,如果找到了相似的childVnode
,那它们将递归进入新的打补丁过程。
源码解析
这次的源码解析写简洁一点,写太多发现自己都不愿意看 (┬_┬)
开始
先来看patch()
函数:
function patch (oldVnode, vnode) { var elm, parent; if (sameVnode(oldVnode, vnode)) { // 相似就去打补丁(增删改) patchVnode(oldVnode, vnode); } else { // 不相似就整个覆盖 elm = oldVnode.elm; parent = api.parentNode(elm); createElm(vnode); if (parent !== null) { api.insertBefore(parent, vnode.elm, api.nextSibling(elm)); removeVnodes(parent, [oldVnode], 0, 0); } } return vnode.elm; }
patch()
函数接收新旧vnode两个参数,传入的这两个参数有个很大的区别:oldVnode的elm
指向真实dom,而vnode的elm
为undefined...但经过patch()
方法后,vnode的elm
也将指向这个(更新过的)真实dom。
判断新旧vnode是否相似的sameVnode()
方法很简单,就是比较tag和key是否一致。
function sameVnode (a, b) { return a.key === b.key && a.tag === b.tag; }
打补丁
对于新旧vnode不一致的处理方法很简单,就是根据vnode创建真实dom,代替oldVnode中的elm
插入DOM文档。
对于新旧vnode一致的处理,就是我们前面经常说到的打补丁了。具体什么是打补丁?看看patchVnode()
方法就知道了:
function patchVnode (oldVnode, vnode) { // 新节点引用旧节点的dom let elm = vnode.elm = oldVnode.elm; const oldCh = oldVnode.children; const ch = vnode.children; // 调用update钩子 if (vnode.data) { updateAttrs(oldVnode, vnode); updateClass(oldVnode, vnode); updateEventListeners(oldVnode, vnode); updateProps(oldVnode, vnode); updateStyle(oldVnode, vnode); } // 判断是否为文本节点 if (vnode.text == undefined) { if (isDef(oldCh) && isDef(ch)) { if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue) } else if (isDef(ch)) { if (isDef(oldVnode.text)) api.setTextContent(elm, '') addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue) } else if (isDef(oldCh)) { removeVnodes(elm, oldCh, 0, oldCh.length - 1) } else if (isDef(oldVnode.text)) { api.setTextContent(elm, '') } } else if (oldVnode.text !== vnode.text) { api.setTextContent(elm, vnode.text) } }
打补丁其实就是调用各种updateXXX()
函数,更新真实dom的各个属性。每个的update函数都类似,就拿updateAttrs()
举例看看:
function updateAttrs (oldVnode, vnode) { let key, cur, old const elm = vnode.elm const oldAttrs = oldVnode.data.attrs || {} const attrs = vnode.data.attrs || {} // 更新/添加属性 for (key in attrs) { cur = attrs[key] old = oldAttrs[key] if (old !== cur) { if (booleanAttrsDict[key] && cur == null) { elm.removeAttribute(key) } else { elm.setAttribute(key, cur) } } } // 删除新节点不存在的属性 for (key in oldAttrs) { if (!(key in attrs)) { elm.removeAttribute(key) } } }
属性(Attribute
)的更新函数的大致思路就是:
遍历vnode属性,如果和oldVnode不一样就调用
setAttribute()
修改;遍历oldVnode属性,如果不在vnode属性中就调用
removeAttribute()
删除。
你会发现里面有个booleanAttrsDict[key]
的判断,是用于判断在不在布尔类型属性字典中。
['allowfullscreen', 'async', 'autofocus', 'autoplay', 'checked', 'compact', 'controls', 'declare', ......]eg:
<video autoplay></video>
![]()
간소화된 가상 노드(vnode)에는 대략 다음과 같은 속성이 포함됩니다.
function updateChildren (parentElm, oldCh, newCh) { let oldStartIdx = 0 let newStartIdx = 0 let oldEndIdx = oldCh.length - 1 let oldStartVnode = oldCh[0] let oldEndVnode = oldCh[oldEndIdx] let newEndIdx = newCh.length - 1 let newStartVnode = newCh[0] let newEndVnode = newCh[newEndIdx] let oldKeyToIdx, idxInOld, elmToMove, before while (oldStartIdx oldEndIdx) { before = isUndef(newCh[newEndIdx+1]) ? null : newCh[newEndIdx + 1].elm addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx, insertedVnodeQueue) } else if (newStartIdx > newEndIdx) { removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx) } }
- 가상 DOM의 비교는 새 노드(vnode)와 이전 노드(oldVnode)의 차이점을 찾아 비교하는 것입니다. 차이점 패치. 일반적인 과정은 다음과 같습니다
- diff 알고리즘
을 사용합니다. 이것이 이 글의 초점이자 난이도입니다.
- 재귀적으로
새 패치 프로세스를 시작한다는 점에 주목할 필요가 있습니다.
소스코드 분석
이번에는 소스코드 분석을 좀 더 간결하게 작성했습니다. 너무 많이 쓰면 읽기 싫을 것 같아요(┬_┬)
Children Compare
프로세스 중에 유사한 childVnode
가 발견되면 시작 patch() code>함수:
rrreee
patch()
함수는 이전 vnode와 새 vnode의 두 매개변수를 받습니다. 전달된 두 매개변수 사이에는 큰 차이가 있습니다. oldVnode의 elm은 Real dom을 가리키고 vnode의 elm
은 정의되지 않았습니다... 하지만 patch()
메서드를 전달한 후 vnode의 elm
code>는 또한 이 (과거 업데이트) 실제 DOM을 가리킬 것입니다.
이전 vnode와 새 vnode가 유사한지 확인하는 sameVnode()
메서드는 매우 간단합니다. 즉,
와 key
elm
대신 DOM 문서를 삽입하는 것입니다. oldVnode. 🎜🎜🎜이전 vnode와 새 vnode를 일관되게🎜 만드는 과정은 앞서 자주 언급했던 패치입니다. 패치란 정확히 무엇입니까? patchVnode()
메서드를 보면 다음과 같은 사실을 알 수 있습니다. 🎜rrreee🎜Patching은 실제로 다양한 updateXXX()
함수를 호출하여 실제 DOM의 다양한 속성을 업데이트합니다. 각 업데이트 함수는 유사합니다. updateAttrs()
를 예로 들면: 🎜rrreee🎜속성(Attribute
)의 업데이트 함수에 대한 일반적인 개념은 다음과 같습니다. 🎜🎜 vnode 속성을 탐색하고, oldVnode와 다른 경우 setAttribute()
를 호출하여 수정합니다. 🎜🎜🎜🎜oldVnode 속성을 탐색하고, vnode 속성에 없으면 다음을 호출합니다. removeAttribute()
를 사용하여 삭제하세요. 🎜🎜🎜🎜내부에는 Boolean 유형 속성 사전에 있는지 판단하는 데 사용되는 booleanAttrsDict[key]
판단이 있음을 알 수 있습니다. 🎜['allowfullscreen', 'async', 'autofocus', 'autoplay', 'checked', 'compact', 'controls', 'declare', ...]🎜eg:<video></video>
, 자동재생을 끄려면 이 속성을 제거해야 합니다. 🎜🎜🎜모든 데이터를 비교한 후에는 하위 노드를 비교할 차례입니다. 먼저 현재 vnode가 텍스트 노드인지 여부를 결정합니다. 텍스트 노드인 경우 하위 노드의 비교를 고려할 필요가 없습니다. 🎜🎜🎜🎜 이전 노드와 새 노드 모두 하위 노드를 갖고 있으면 하위 노드 비교를 입력합니다(diff 알고리즘). 🎜🎜🎜🎜새 노드에는 하위 노드가 있지만 이전 노드에는 없으면 루프에서 dom 노드를 만듭니다. 🎜새 노드에는 하위 노드가 없지만 이전 노드에는 하위 노드가 있습니다. 그런 다음 루프에서 dom 노드를 삭제합니다. 🎜🎜🎜🎜후자의 두 경우는 상대적으로 간단합니다. 첫 번째 경우인 🎜하위 노드 비교🎜를 직접 분석합니다. 🎜🎜diff 알고리즘🎜🎜하위 노드 비교 부분에는 코드가 많습니다. 먼저 원리에 대해 이야기한 후 코드를 게시하겠습니다. 먼저 하위 노드를 비교하는 그림을 살펴보겠습니다. 🎜🎜🎜🎜그림의
oldCh
및newCh
는 각각 이전 및 새 하위 노드 배열을 나타냅니다. 이들은 자체 헤드 및 테일 포인터oldStartIdx
,oldEndIdx
,newStartIdx
,newEndIdx
, 배열은 vnode를 저장하므로 이해하기 쉽도록 a, b, c, d 등으로 대체됩니다. 다양한 유형의 레이블(p,span,p의 vnode 객체)을 나타냅니다.oldCh
和newCh
分别表示新旧子节点数组,它们都有自己的头尾指针oldStartIdx
,oldEndIdx
,newStartIdx
,newEndIdx
,数组里面存储的是vnode,为了容易理解就用a,b,c,d等代替,它们表示不同类型标签(p,span,p)的vnode对象。子节点的比较实质上就是循环进行头尾节点比较。循环结束的标志就是:旧子节点数组或新子节点数组遍历完,(即
oldStartIdx > oldEndIdx || newStartIdx > newEndIdx
)。大概看一下循环流程:
第一步 头头比较。若相似,旧头新头指针后移(即
oldStartIdx++
&&newStartIdx++
),真实dom不变,进入下一次循环;不相似,进入第二步。第二步 尾尾比较。若相似,旧尾新尾指针前移(即
oldEndIdx--
&&newEndIdx--
),真实dom不变,进入下一次循环;不相似,进入第三步。第三步 头尾比较。若相似,旧头指针后移,新尾指针前移(即
oldStartIdx++
&&newEndIdx--
),未确认dom序列中的头移到尾,进入下一次循环;不相似,进入第四步。第四步 尾头比较。若相似,旧尾指针前移,新头指针后移(即
oldEndIdx--
&&newStartIdx++
),未确认dom序列中的尾移到头,进入下一次循环;不相似,进入第五步。第五步 若节点有key且在旧子节点数组中找到sameVnode(tag和key都一致),则将其dom移动到当前真实dom序列的头部,新头指针后移(即
newStartIdx++
);否则,vnode对应的dom(vnode[newStartIdx].elm
)插入当前真实dom序列的头部,新头指针后移(即newStartIdx++
)。先看看没有key的情况,放个动图看得更清楚些!
相信看完图片有更好的理解到diff算法的精髓,整个过程还是比较简单的。上图中一共进入了6次循环,涉及了每一种情况,逐个叙述一下:
第一次是头头相似(都是
a
),dom不改变,新旧头指针均后移。a
节点确认后,真实dom序列为:a,b,c,d,e,f
,未确认dom序列为:b,c,d,e,f
;第二次是尾尾相似(都是
f
),dom不改变,新旧尾指针均前移。f
节点确认后,真实dom序列为:a,b,c,d,e,f
,未确认dom序列为:b,c,d,e
;第三次是头尾相似(都是
b
),当前剩余真实dom序列中的头移到尾,旧头指针后移,新尾指针前移。b
节点确认后,真实dom序列为:a,c,d,e,b,f
,未确认dom序列为:c,d,e
;第四次是尾头相似(都是
e
),当前剩余真实dom序列中的尾移到头,旧尾指针前移,新头指针后移。e
节点确认后,真实dom序列为:a,e,c,d,b,f
,未确认dom序列为:c,d
;第五次是均不相似,直接插入到未确认dom序列头部。
g
节点插入后,真实dom序列为:a,e,g,c,d,b,f
,未确认dom序列为:c,d
;第六次是均不相似,直接插入到未确认dom序列头部。
h
节点插入后,真实dom序列为:a,e,g,h,c,d,b,f
,未确认dom序列为:c,d
;但结束循环后,有两种情况需要考虑:
新的字节点数组(newCh)被遍历完(
newStartIdx > newEndIdx
)。那就需要把多余的旧dom(oldStartIdx -> oldEndIdx
)都删除,上述例子中就是c,d
;新的字节点数组(oldCh)被遍历完(
하위 노드 비교는 기본적으로 헤드 노드와 테일 노드의 루프 비교입니다. 루프 끝의 신호는 다음과 같습니다. 이전 하위 노드 배열 또는 새 하위 노드 배열이 탐색되었습니다(예:oldStartIdx > oldEndIdx
)。那就需要把多余的新dom(newStartIdx -> newEndIdx
oldStartIdx > oldEndIdx || newStartIdx > newEndIdx
). 유통 과정을 대략적으로 살펴보세요. 🎜🎜키가 없는 상황을 먼저 살펴보고, 좀 더 명확하게 볼 수 있도록 애니메이션을 넣어보겠습니다! C
- 🎜첫 번째 단계는 직접 비교입니다. . 유사하면 이전 헤드 포인터와 새 헤드 포인터가 뒤로 이동하고(예:
oldStartIdx++
&&newStartIdx++
) 실제 DOM은 변경되지 않고 그대로 유지되며 다음 주기로 들어갑니다. 유사하지 않으면 두 번째 단계로 들어갑니다. 🎜- 🎜두 번째 단계는 꼬리-꼬리 비교입니다. 유사하면 이전 끝 포인터와 새 끝 포인터가 앞으로 이동하고(예:
oldEndIdx--
&&newEndIdx--
) 실제 DOM은 변경되지 않고 그대로 유지되며 다음 주기 유사하지 않으면 첫 번째 단계가 입력됩니다. 🎜- 🎜세 번째 단계는 직접 비교입니다. 유사하다면 이전 헤드 포인터는 뒤로 이동하고 새 테일 포인터는 앞으로 이동합니다(예:
oldStartIdx++
&&newEndIdx--
). 확인되지 않은 dom 시퀀스의 헤드가 이동됩니다. 끝까지 가면 다음 단계로 들어갑니다. 유사하지 않으면 4단계로 이동합니다. 🎜- 🎜4단계 꼬리와 머리를 비교하세요. 유사하면 이전 꼬리 포인터는 앞으로 이동하고 새 헤드 포인터는 뒤로 이동합니다(예:
oldEndIdx--
&&newStartIdx++
). 시퀀스가 처음으로 이동하고 다음 시간이 유사하지 않으면 5단계로 이동합니다. 🎜- 🎜5단계: 노드에 키가 있고 이전 하위 노드 배열에서 동일한 Vnode가 발견되면(태그와 키가 모두 일관됨) 해당 DOM을 현재 실제 DOM의 헤드로 이동합니다. 시퀀스, 새 헤드 포인터 뒤로 이동(예:
newStartIdx++
). 그렇지 않으면 vnode(vnode[newStartIdx].elm
)에 해당하는 dom이 현재 포인터의 헤드에 삽입됩니다. 실제 DOM 시퀀스이며 새 헤드 포인터가 뒤로 이동합니다(즉,newStartIdx++
). 🎜🎜 🎜그림을 읽고 나면 diff 알고리즘의 본질을 더 잘 이해하게 될 것이라고 믿습니다. 전체 과정은 비교적 간단합니다. 위 그림에서는 각 상황에 대해 총 6개의 사이클이 입력되었습니다. 하나씩 설명하겠습니다. 🎜
🎜그러나 루프를 종료한 후 고려해야 할 두 가지 상황이 있습니다: 🎜
- 🎜처음은 비슷합니다(둘 다 비슷합니다).
a
), dom은 변경되지 않고 이전 헤드 포인터와 새 헤드 포인터가 뒤로 이동됩니다.a
노드가 확인된 후 실제 dom 시퀀스는a,b,c,d,e,f
이고 확인되지 않은 dom 시퀀스는b입니다. ,c,d ,e,f
;🎜- 🎜두 번째로 tail과 tail이 유사할 때(둘 다
f
) dom은 변경되지 않으며, 이전 및 새 꼬리 포인터가 앞으로 이동됩니다.f
노드가 확인된 후 실제 DOM 시퀀스는a,b,c,d,e,f
이고 확인되지 않은 DOM 시퀀스는b입니다. ,c,d ,e
;🎜- 🎜세 번째는 머리와 꼬리가 비슷하다는 것입니다(둘 다
b
). 현재 남아 있는 실수의 머리 dom 시퀀스는 끝으로 이동하고 이전 헤드 포인터는 뒤로 이동하고 새 테일 포인터는 앞으로 이동합니다.b
노드가 확인된 후 실제 DOM 시퀀스는a,c,d,e,b,f
이고 확인되지 않은 DOM 시퀀스는c입니다. ,d,e
;🎜- 🎜네 번째는 꼬리와 머리가 유사하다는 것입니다(둘 다
e
). 꼬리는 현재 남아 있는 실제 DOM 시퀀스에 있습니다. 가 헤드로 이동하고 이전 테일 포인터가 앞으로 이동하고 새 헤드 포인터가 뒤로 이동합니다.e
노드가 확인된 후 실제 dom 시퀀스는a,e,c,d,b,f
이고 확인되지 않은 dom 시퀀스는c입니다. ,d
code>;🎜- 🎜5번째는 유사하지 않으며 확인되지 않은 dom 시퀀스의 헤드에 직접 삽입됩니다.
g
노드가 삽입된 후 실제 dom 시퀀스는a,e,g,c,d,b,f
이고 확인되지 않은 dom 시퀀스는입니다. >c,d
;🎜- 🎜6번째 시간은 유사하지 않으며 확인되지 않은 dom 시퀀스의 헤드에 직접 삽입됩니다.
h
노드가 삽입된 후 실제 dom 시퀀스는a,e,g,h,c,d,b,f
이고 확인되지 않은 dom 시퀀스는 다음과 같습니다.c ,d
;🎜
- 🎜New bytes 포인트 배열(newCh)이 순회됩니다(
newStartIdx > newEndIdx
). 그런 다음 중복된 이전 DOM(oldStartIdx -> oldEndIdx
)을 모두 삭제해야 합니다. 위의 예에서는c,d
; >🎜New 바이트 포인트 배열(oldCh)이 탐색됩니다(oldStartIdx > oldEndIdx
). 그런 다음 추가 새 DOM(newStartIdx -> newEndIdx
)을 모두 추가해야 합니다. 🎜上面说了这么多都是没有key的情况,说添加了
:key
可以优化v-for
的性能,到底是怎么回事呢?因为v-for
大部分情况下生成的都是相同tag
的标签,如果没有key标识,那么相当于每次头头比较都能成功。你想想如果你往v-for
绑定的数组头部push数据,那么整个dom将全部刷新一遍(如果数组每项内容都不一样),那加了key
会有什么帮助呢?这边引用一张图:
有
key
的情况,其实就是多了一步匹配查找的过程。也就是上面循环流程中的第五步,会尝试去旧子节点数组中找到与当前新子节点相似的节点,减少dom的操作!有兴趣的可以看看代码:
function updateChildren (parentElm, oldCh, newCh) { let oldStartIdx = 0 let newStartIdx = 0 let oldEndIdx = oldCh.length - 1 let oldStartVnode = oldCh[0] let oldEndVnode = oldCh[oldEndIdx] let newEndIdx = newCh.length - 1 let newStartVnode = newCh[0] let newEndVnode = newCh[newEndIdx] let oldKeyToIdx, idxInOld, elmToMove, before while (oldStartIdx oldEndIdx) { before = isUndef(newCh[newEndIdx+1]) ? null : newCh[newEndIdx + 1].elm addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx, insertedVnodeQueue) } else if (newStartIdx > newEndIdx) { removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx) } }
위 내용은 Vue의 가상 돔 비교 원리 소개(예제 설명)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

Python과 JavaScript는 커뮤니티, 라이브러리 및 리소스 측면에서 고유 한 장점과 단점이 있습니다. 1) Python 커뮤니티는 친절하고 초보자에게 적합하지만 프론트 엔드 개발 리소스는 JavaScript만큼 풍부하지 않습니다. 2) Python은 데이터 과학 및 기계 학습 라이브러리에서 강력하며 JavaScript는 프론트 엔드 개발 라이브러리 및 프레임 워크에서 더 좋습니다. 3) 둘 다 풍부한 학습 리소스를 가지고 있지만 Python은 공식 문서로 시작하는 데 적합하지만 JavaScript는 MDNWebDocs에서 더 좋습니다. 선택은 프로젝트 요구와 개인적인 이익을 기반으로해야합니다.

C/C에서 JavaScript로 전환하려면 동적 타이핑, 쓰레기 수집 및 비동기 프로그래밍으로 적응해야합니다. 1) C/C는 수동 메모리 관리가 필요한 정적으로 입력 한 언어이며 JavaScript는 동적으로 입력하고 쓰레기 수집이 자동으로 처리됩니다. 2) C/C를 기계 코드로 컴파일 해야하는 반면 JavaScript는 해석 된 언어입니다. 3) JavaScript는 폐쇄, 프로토 타입 체인 및 약속과 같은 개념을 소개하여 유연성과 비동기 프로그래밍 기능을 향상시킵니다.

각각의 엔진의 구현 원리 및 최적화 전략이 다르기 때문에 JavaScript 엔진은 JavaScript 코드를 구문 분석하고 실행할 때 다른 영향을 미칩니다. 1. 어휘 분석 : 소스 코드를 어휘 단위로 변환합니다. 2. 문법 분석 : 추상 구문 트리를 생성합니다. 3. 최적화 및 컴파일 : JIT 컴파일러를 통해 기계 코드를 생성합니다. 4. 실행 : 기계 코드를 실행하십시오. V8 엔진은 즉각적인 컴파일 및 숨겨진 클래스를 통해 최적화하여 Spidermonkey는 유형 추론 시스템을 사용하여 동일한 코드에서 성능이 다른 성능을 제공합니다.

실제 세계에서 JavaScript의 응용 프로그램에는 서버 측 프로그래밍, 모바일 애플리케이션 개발 및 사물 인터넷 제어가 포함됩니다. 1. 서버 측 프로그래밍은 Node.js를 통해 실현되며 동시 요청 처리에 적합합니다. 2. 모바일 애플리케이션 개발은 재교육을 통해 수행되며 크로스 플랫폼 배포를 지원합니다. 3. Johnny-Five 라이브러리를 통한 IoT 장치 제어에 사용되며 하드웨어 상호 작용에 적합합니다.

일상적인 기술 도구를 사용하여 기능적 다중 테넌트 SaaS 응용 프로그램 (Edtech 앱)을 구축했으며 동일한 작업을 수행 할 수 있습니다. 먼저, 다중 테넌트 SaaS 응용 프로그램은 무엇입니까? 멀티 테넌트 SAAS 응용 프로그램은 노래에서 여러 고객에게 서비스를 제공 할 수 있습니다.

이 기사에서는 Contrim에 의해 확보 된 백엔드와의 프론트 엔드 통합을 보여 주며 Next.js를 사용하여 기능적인 Edtech SaaS 응용 프로그램을 구축합니다. Frontend는 UI 가시성을 제어하기 위해 사용자 권한을 가져오고 API가 역할 기반을 준수하도록합니다.

JavaScript는 현대 웹 개발의 핵심 언어이며 다양성과 유연성에 널리 사용됩니다. 1) 프론트 엔드 개발 : DOM 운영 및 최신 프레임 워크 (예 : React, Vue.js, Angular)를 통해 동적 웹 페이지 및 단일 페이지 응용 프로그램을 구축합니다. 2) 서버 측 개발 : Node.js는 비 차단 I/O 모델을 사용하여 높은 동시성 및 실시간 응용 프로그램을 처리합니다. 3) 모바일 및 데스크탑 애플리케이션 개발 : 크로스 플랫폼 개발은 개발 효율을 향상시키기 위해 반응 및 전자를 통해 실현됩니다.

JavaScript의 최신 트렌드에는 Typescript의 Rise, 현대 프레임 워크 및 라이브러리의 인기 및 WebAssembly의 적용이 포함됩니다. 향후 전망은보다 강력한 유형 시스템, 서버 측 JavaScript 개발, 인공 지능 및 기계 학습의 확장, IoT 및 Edge 컴퓨팅의 잠재력을 포함합니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

Eclipse용 SAP NetWeaver 서버 어댑터
Eclipse를 SAP NetWeaver 애플리케이션 서버와 통합합니다.

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

Atom Editor Mac 버전 다운로드
가장 인기 있는 오픈 소스 편집기

드림위버 CS6
시각적 웹 개발 도구

에디트플러스 중국어 크랙 버전
작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음
