大厂技术 高级前端 Node进阶
点击上方 程序员成长指北,关注公众号
回复1,加入高级Node交流群
原文链接: https://juejin.cn/post/7113503219904430111?share_token=a2d6b49c-d8ce-4448-acd3-d71bbc6e228d 作者:小白
背景
随着SPA大规模的应用,紧接着就带来一个新问题:一个规模化应用需要拆分。
一方面功能快速增加导致打包时间成比例上升,而紧急发布时要求是越短越好,这是矛盾的。另一方面当一个代码库集成了所有功能时,日常协作绝对是非常困难的。而且最近十多年,前端技术的发展是非常快的,每隔两年就是一个时代,导致同志们必须升级项目甚至于换一个框架。但如果大家想在一个规模化应用中一个版本做好这件事,基本上是不可能的。
最早的解决方案是采用iframe的方法,根据功能主要模块拆分规模化应用,子应用之间使用跳转。但这个方案最大问题是导致页面重新加载和白屏。
那有什么好的解决方案呢?微前端这样具有跨应用的解决方案在此背景下应运而生了!
微前端的概念
微前端是什么:微前端是一种类似于微服务的架构,是一种由独立交付的多个前端应用组成整体的架构风格,将前端应用分解成一些更小、更简单的能够独立开发、测试、部署的应用,而在用户看来仍然是内聚的单个产品。有一个基座应用 (主应用),来管理各个子应用 的加载和卸载。
f135ab0912746bd6.png
所以微前端不是指具体的库,不是指具体的框架,不是指具体的工具,而是一种理想与架构模式。
微前端的核心三大原则就是:独立运行、独立部署、独立开发
微前端的优势
采用微前端架构的好处就是,将这些小型应用融合为一个完整的应用,或者将原本运行已久、没有关联的几个应用融合为一个应用可以将多个项目融合为一,又可以减少项目之间的耦合,提升项目扩展性。
实现微前端的几种方式
微前端框架的分类
Single-spa
single-spa
是一个很好的微前端基础框架,而qiankun
框架就是基于single-spa
来实现的,在single-spa
的基础上做了一层封装,也解决了single-spa
的一些缺陷。
首先我们先来了解该如何使用single-spa
来完成微前端的搭建。
single-spa.jpg
Single-spa实现原理
首先在基座应用中注册所有App的路由,single-spa
保存各子应用的路由映射关系,充当微前端控制器Controler ,。URL响应时,匹配子应用路由并加载渲染子应用。上图便是对single-spa
完整的描述。
有了理论基础,接下来,我们来看看代码层面时如何使用的。
以下以Vue工程为例基座构建single-spa,在Vue工程入口文件main.js完成基座的配置。
基座配置
//main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import { registerApplication, start } from 'single-spa'
Vue.config.productionTip = false
const mountApp = (url) => {
return new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = url
script.onload = resolve
script.onerror = reject
// 通过插入script标签的方式挂载子应用
const firstScript = document.getElementsByTagName('script')[0]
// 挂载子应用
firstScript.parentNode.insertBefore(script, firstScript)
})
}
const loadApp = (appRouter, appName) => {
// 远程加载子应用
return async () => {
//手动挂载子应用
await mountApp(appRouter + '/js/chunk-vendors.js')
await mountApp(appRouter + '/js/app.js')
// 获取子应用生命周期函数
return window[appName]
}
}
// 子应用列表
const appList = [
{
// 子应用名称
name: 'app1',
// 挂载子应用
app: loadApp('http://localhost:8083', 'app1'),
// 匹配该子路由的条件
activeWhen: location => location.pathname.startsWith('/app1'),
// 传递给子应用的对象
customProps: {}
},
{
name: 'app2',
app: loadApp('http://localhost:8082', 'app2'),
activeWhen: location => location.pathname.startsWith('/app2'),
customProps: {}
}
]
// 注册子应用
appList.map(item => {
registerApplication(item)
})
// 注册路由并启动基座
new Vue({
router,
mounted() {
start()
},
render: h => h(App)
}).$mount('#app')
构建基座的核心是:配置子应用信息,通过registerApplication 注册子应用,在基座工程挂载阶段start 启动基座。
子应用配置
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import singleSpaVue from 'single-spa-vue'
Vue.config.productionTip = false
const appOptions = {
el: '#microApp',
router,
render: h => h(App)
}
// 支持应用独立运行、部署,不依赖于基座应用
// 如果不是微应用环境,即启动自身挂载的方式
if (!process.env.isMicro) {
delete appOptions.el
new Vue(appOptions).$mount('#app')
}
// 基于基座应用,导出生命周期函数
const appLifecycle = singleSpaVue({
Vue,
appOptions
})
// 抛出子应用生命周期
// 启动生命周期函数
export const bootstrap = (props) => {
console.log('app2 bootstrap')
return appLifecycle.bootstrap(() => { })
}
// 挂载生命周期函数
export const mount = (props) => {
console.log('app2 mount')
return appLifecycle.mount(() => { })
}
// 卸载生命周期函数
export const unmount = (props) => {
console.log('app2 unmount')
return appLifecycle.unmount(() => { })
}
配置子应用为umd打包方式
//vue.config.js
const package = require('./package.json')
module.exports = {
// 告诉子应用在这个地址加载静态资源,否则会去基座应用的域名下加载
publicPath: '//localhost:8082',
// 开发服务器
devServer: {
port: 8082
},
configureWebpack: {
// 导出umd格式的包,在全局对象上挂载属性package.name,基座应用需要通过这个
// 全局对象获取一些信息,比如子应用导出的生命周期函数
output: {
// library的值在所有子应用中需要唯一
library: package.name,
libraryTarget: 'umd'
}
}
配置子应用环境变量
// .env.micro
NODE_ENV=development
VUE_APP_BASE_URL=/app2
isMicro=true
子应用配置的核心是用singleSpaVue生成子路由配置后,必须要抛出其生命周期函数 。
用以上方式便可轻松实现一个简单的微前端应用了。
那么我们有single-spa
这种微前端解决方案,为什么还需要qiankun
呢?
相比于single-spa
,qiankun
他解决了JS沙盒环境,不需要我们自己去进行处理。在single-spa
的开发过程中,我们需要自己手动的去写调用子应用JS的方法(如上面的 createScript方法),而qiankun
不需要,乾坤只需要你传入响应的apps的配置即可,会帮助我们去加载。
Qiankun
Qiankun的优势
基于 single-spa 封装,提供了更加开箱即用的 API。
技术栈无关 ,任意技术栈的应用均可 使用/接入,不论是 React/Vue/Angular/JQuery 还是其他等框架。
HTML Entry 接入方式 ,让你接入微应用像使用 iframe 一样简单。
样式隔离 ,确保微应用之间样式互相不干扰。
JS 沙箱 ,确保微应用之间 全局变量/事件 不冲突。
资源预加载 ,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度。
基座配置
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'reactApp',
entry: '//localhost:3000',
container: '#container',
activeRule: '/app-react',
},
{
name: 'vueApp',
entry: '//localhost:8080',
container: '#container',
activeRule: '/app-vue',
},
{
name: 'angularApp',
entry: '//localhost:4200',
container: '#container',
activeRule: '/app-angular',
},
]);
// 启动 qiankun
start();
子应用配置
以 create react app
生成的 react 16
项目为例,搭配 react-router-dom
5.x。
1.在 src
目录新增 public-path.js
,解决子应用挂载时,访问静态资源冲突
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
2.设置 history
模式路由的 base
:
3.入口文件 index.js
修改,为了避免根 id #root
与其他的 DOM 冲突,需要限制查找范围。
import './public-path';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
function render(props) {
const { container } = props;
ReactDOM.render(, container ? container.querySelector('#root') :
document.querySelector('#root'));
}
if (!window.__POWERED_BY_QIANKUN__) {
render({});
}
export async function bootstrap() {
console.log('[react16] react app bootstraped');
}
export async function mount(props) {
console.log('[react16] props from main framework', props);
render(props);
}
export async function unmount(props) {
const { container } = props;
ReactDOM.unmountComponentAtNode(container ? container.querySelector('#root') :
document.querySelector('#root'));
}
4.修改 webpack
配置
安装插件 @rescripts/cli
,当然也可以选择其他的插件,例如 react-app-rewired
。
npm i -D @rescripts/cli
根目录新增 .rescriptsrc.js
:
const { name } = require('./package');
module.exports = {
webpack: (config) => {
config.output.library = `${name}-[name]`;
config.output.libraryTarget = 'umd';
config.output.jsonpFunction = `webpackJsonp_${name}`;
config.output.globalObject = 'window';
return config;
},
devServer: (_) => {
const config = _;
config.headers = {
'Access-Control-Allow-Origin': '*',
};
config.historyApiFallback = true;
config.hot = false;
config.watchContentBase = false;
config.liveReload = false;
return config;
},
};
以上对Qiankun的使用可以看出,与single-spa使用过程很相似。不同的是,Qiankun的使用过程更简便了。一些内置的操作交由给Qiankun内部实现。这是一种IOC思想的实现 ,我们只管面向容器化开发,其他操作交给Qiankun框架管理。
Micro-app
micro-app
并没有沿袭single-spa
的思路,而是借鉴了WebComponent的思想,通过CustomElement结合自定义的ShadowDom,将微前端封装成一个类WebComponent组件,从而实现微前端的组件化渲染。并且由于自定义ShadowDom的隔离特性,micro-app
不需要像single-spa
和qiankun
一样要求子应用修改渲染逻辑并暴露出方法,也不需要修改webpack配置,是目前市面上接入微前端成本最低的方案。
WebComponent的概念
WebComponent 是HTML5提供的一套自定义元素的接口,WebComponent 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的 web 应用中使用它们。以上是MDN社区对WebComponent的解释。
Custom elements(自定义元素): 一组 JavaScript API,允许您定义 custom elements 及其行为,然后可以在您的用户界面中按照需要使用它们。
Shadow DOM(影子 DOM) :一组 JavaScript API,用于将封装的“影子”DOM 树附加到元素(与主文档 DOM 分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。
HTML templates(HTML 模板): 和
元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。
接下来用一个小例子更快来理解WebComponent的概念。
一个存在组件内交互的WebComponent
// 基于HTMLElement自定义组件元素
class CounterElement extends HTMLElement {
// 在构造器中生成shadow节点
constructor() {
super();
this.counter = 0;
// 打开影子节点
// 影子节点是为了隔离外部元素的影响
const shadowRoot = this.attachShadow({ mode: 'open' });
// 定义组件内嵌样式
const styles = `
#counter-increment {
width: 60px;
height: 30px;
margin: 20px;
background: none;
border: 1px solid black;
}
`;
// 定义组件HTMl结构
shadowRoot.innerHTML = `
Counter
Button
; 0 ;
+
`;
// 获取+号按钮及数值内容
this.incrementButton = this.shadowRoot.querySelector('#counter-increment');
this.counterValue = this.shadowRoot.querySelector('#counter-value');
// 实现点击组件内事件驱动
this.incrementButton.addEventListener("click", this.decrement.bind(this));
}
increment() {
this.counter++
this.updateValue();
}
// 替换counter节点内容,达到更新数值的效果
updateValue() {
this.counterValue.innerHTML = this.counter;
}
}
// 在真实dom上,生成自定义组件元素
customElements.define('counter-element', CounterElement);
有了对WebComponent的理解,接下来,我们更明白了Micro-app的优势。
micro-app的优势 d879637b4bb34253.png
使用简单
我们将所有功能都封装到一个类WebComponent组件中,从而实现在基座应用中嵌入一行代码即可渲染一个微前端应用。
同时micro-app
还提供了js沙箱
、样式隔离
、元素隔离
、预加载
、数据通信
、静态资源补全
等一系列完善的功能。
零依赖
micro-app
没有任何依赖,这赋予它小巧的体积和更高的扩展性。
兼容所有框架
为了保证各个业务之间独立开发、独立部署的能力,micro-app
做了诸多兼容,在任何技术框架中都可以正常运行。
基座的简易配置
基座存在预加载子应用、父子应用通信、公共文件共享等等
// index.js
import React from "react"
import ReactDOM from "react-dom"
import App from './App'
import microApp from '@micro-zoe/micro-app'
const appName = 'my-app'
// 预加载
microApp.preFetch([
{ name: appName, url: 'xxx' }
])
// 基座向子应用数据通信
microApp.setData(appName, { type: '新的数据' })
// 获取指定子应用数据
const childData = microApp.getData(appName)
microApp.start({
// 公共文件共享
globalAssets: {
js: ['js地址1', 'js地址2', ...], // js地址
css: ['css地址1', 'css地址2', ...], // css地址
}
})
分配一个路由给子应用
// router.js
import { BrowserRouter, Switch, Route } from 'react-router-dom'
export default function AppRoute () {
return (
)
}
子应用的简易配置
// index.js
import React from "react"
import ReactDOM from "react-dom"
import App from './App'
import microApp from '@micro-zoe/micro-app'
const appName = 'my-app'
// 子应用运行时,切换静态资源访问路径
if (window.__MICRO_APP_ENVIRONMENT__) {
__webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__
}
// 基子应用向基座发送数据
// dispatch只接受对象作为参数
window.microApp.dispatch({ type: '子应用发送的数据' })
// 获取基座数据
const data = window.microApp.getData() // 返回基座下发的data数据
//性能优化,umd模式
// 如果子应用渲染和卸载不频繁,那么使用默认模式即可,如果子应用渲染和卸载非常频繁建议使用umd模式
// 将渲染操作放入 mount 函数 -- 必填
export function mount() {
ReactDOM.render(, document.getElementById("root"))
}
// 将卸载操作放入 unmount 函数 -- 必填
export function unmount() {
ReactDOM.unmountComponentAtNode(document.getElementById("root"))
}
// 微前端环境下,注册mount和unmount方法
if (window.__MICRO_APP_ENVIRONMENT__) {
window[`micro-app-${window.__MICRO_APP_NAME__}`] = { mount, unmount }
} else {
// 非微前端环境直接渲染
mount()
}
设置子应用路由
import { BrowserRouter, Switch, Route } from 'react-router-dom'
export default function AppRoute () {
return (
// 设置基础路由,子应用可以通过window.__MICRO_APP_BASE_ROUTE__获取基座下发的baseroute,
// 如果没有设置baseroute属性,则此值默认为空字符串
...
)
}
以上便是Micro-app的用法
Module Federation
Module Federation是Webpack5提出的概念,module federation用来解决多个应用之间代码共享 的问题,让我们更加优雅的实现跨应用 的代码共享。
MF 想做的事和微前端想解决的问题是类似的,把一个应用进行拆分成多个应用,每个应用可独立开发,独立部署,一个应用可以动态加载 并运行另一个应用的代码,并实现应用之间的依赖共享。
为了实现这样的功能, MF在设计上提出了这几个核心概念。
Container
一个被 ModuleFederationPlugin 打包出来的模块被称为 Container 。 通俗点讲就是,如果我们的一个应用使用了 ModuleFederationPlugin 构建,那么它就成为一个 Container ,它可以加载其他的 Container ,可以被其他的 Container 所加载。
Host&Remote
从消费者和生产者的角度看 Container ,Container 又可被称作 Host 或 Remote 。
Host
:消费方,它动态加载并运行其他 Container 的代码。
Remote
:提供方,它暴露属性 (如组件、方法等)供 Host 使用
可以知道,这里的 Host 和 Remote 是相对的,因为 一个 Container 既可以作为 Host ,也可以作为 Remote 。
Shared
一个 Container 可以 Shared 它的依赖(如 react、react-dom)给其他 Container 使用,也就是共享依赖。
微信图片_20220626184254.png 微信图片_20220626184305.png
以上是webpack5与之前版本的模块管理对比图
微应用配置
通过webpack5的配置达成微应用的效果
// 配置webpack.config.js
const { ModuleFederationPlugin } = require("webpack").container;
new ModuleFederationPlugin({
name: "appA",
//出口文件
filename: "remoteEntry.js",
//暴露可访问的组件
exposes: {
"./input": "./src/input",
},
//或者其他模块的组件
//如果把这一模块当作基座模块的话,
//这里应该配置其他子应用模块的入口文件
remotes: {
appB: "appB@http://localhost:3002/remoteEntry.js",
},
//共享依赖,其他模块不需要再次下载,便可使用
shared: ['react', 'react-dom'],
})
以上便是我对微应用架构的理解,以及微应用架构技术的演变过程。不难看出,这些技术的演变都朝着易用性和可拓展性的方向演进。其中技术也有其时代的局限性,不过思想和技术总是在不断进步的。这几类技术选型都有其优缺点,各有千秋,我们可以根据不同的需要选择不同的技术来构建应用。
下列是本文写作时的参考资料:
single-spa: zh-hans.single-spa.js.org/docs/gettin…
qiankun: qiankun.umijs.org/zh/guide
WebComponent: developer.mozilla.org/zh-CN/docs/…
micro-app: cangdu.org/micro-app/d…
Node 社群
我组建了一个氛围特别好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你对Node.js学习感兴趣的话(后续有计划也可以),我们可以一起进行Node.js相关的交流、学习、共建。下方加 考拉 好友回复「Node」即可。
如果你觉得这篇内容对你有帮助,我想请你帮我2个小忙:
1. 点个「在看」,让更多人也能看到这篇文章2. 订阅官方博客 www.inode.club 让我们一起成长
点赞和在看就是最大的支持
你可能感兴趣的:(vue,react,js,javascript,java)
ollama-chat-ui-vue,一个可以用vue对接ollama的开源项目,可接入deepSeek
是你的小熊啊
ui vue.js 前端 ai
ollama-chat-ui-vue使用vue3+vite+elementUi搭建的前端chat,通过ollama可与模型对话,目前支持独立思考,切换模型(联网查询后续支持)github地址:ollama-chat-ui-vue制作不易github点点star,谢谢前置工作安装ollama,ollama官网地址安装完ollama后,打开cmd,下载模型(我选了个最小的模型,模型地址)ollamar
Java中的hashCode和equals方法之间有什么联系
我荔枝呢!
java 开发语言 equals hashCode
定义及作用:equals方法:用于判断两个对象的内容是否相等。默认情况下,它比较的是对象的引用地址,在很多类中会重写该方法以实现基于内容的比较。hashCode方法:返回对象的哈希码值,是一个整数。哈希码主要用于在哈希表等数据结构中快速定位和存储对象,提高数据的存储和查找效率。两者关系:一致性:如果两个对象通过equals方法比较返回true,即两个对象相等,那么它们的hashCode值必须相等。
力扣每日一练之字符串Day6
京与旧铺
LeetCode刷起来 leetcode java 算法
力扣每日一练之字符串Day6前面的话大家好!本篇文章将介绍2周搞定数据结构的题,本文将以三道题作为背景,介绍经典的数独以及排序算法,展示语言为java(博主学习语言为java)。今天呢,是博主开始刷力扣的第五天,如果有想要开始准备自己的算法面试的同学,可以跟着我的脚步一起,共同进步。大家都是并肩作战的伙伴,一起努力奋力前行,路漫漫其修远兮,吾将上下而求索,相信我们一定都可以拿到自己期望的offer
vue3和vue2的组件开发有什么区别
IT木昜
vue.js
Vue3和Vue2在组件开发上存在不少差异,下面从多个方面详细介绍:响应式原理Vue2:用Object.defineProperty()方法来实现响应式。打个比方,它就像给对象的每个属性都安排了一个“小管家”,属性被访问或修改时,“小管家”就去通知相关的地方更新。但这个方法有个局限,比如它不能很好地检测对象新增属性或删除属性的变化,你要是给对象新添加一个属性,“小管家”可能注意不到,页面也就不会自
HTML5+CSS3【容器元素、 HTML5新增布局标签、视频和音频 、HTML5新增标签】(五)-全面详解(学习总结---从入门到深化)
童小纯
前端系列---从入门到深化 css3 html5
作者简介:大家好,我是小童,Java开发工程师,CSDN博客博主,Java领域新星创作者系列专栏:前端、Java、Java中间件大全、微信小程序、微信支付、若依框架、Spring全家桶如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步如果感觉博主的文章还不错的话,请三连支持一下博主哦博主正在努力完成2023计划中:以梦为马,扬帆起航,2023追梦人目录容器元素(div)学习效果反馈HTM
Bootstrap CSS 概览
froginwe11
开发语言
BootstrapCSS概览引言Bootstrap是一个流行的前端框架,它可以帮助开发者快速构建响应式、移动优先的网站和应用程序。Bootstrap使用CSS、HTML和JavaScript来构建界面,其中CSS部分提供了丰富的样式和组件,使得开发者可以轻松实现各种设计效果。本文将为您提供一个关于BootstrapCSS的概览,帮助您了解其核心功能和用法。BootstrapCSS简介Bootstr
jQuery AJAX 方法详解
froginwe11
开发语言
jQueryAJAX方法详解引言随着互联网技术的不断发展,前端开发领域的技术也在不断更新迭代。jQuery作为一种广泛使用的前端JavaScript库,极大地简化了DOM操作和事件处理。在众多jQuery功能中,AJAX(AsynchronousJavaScriptandXML)方法尤为突出,它允许我们在不重新加载整个页面的情况下与服务器进行异步通信。本文将详细介绍jQueryAJAX方法的使用,
Java每日精进·45天挑战·Day10
云朵大王
java python 开发语言
第一部分:在Java中统计宝石数量在编程中,字符串操作是一个常见的任务。今天,我们将讨论一个关于字符串匹配的问题:给定一个代表宝石类型的字符串jewels和一个代表你所拥有的石头类型的字符串stones,我们需要统计stones中有多少石头是宝石。这个问题看似简单,但它考察的是字符串遍历和字符匹配的基本技巧。我们将使用Java语言来实现这个解决方案。问题描述输入:两个字符串jewels和stone
Java每日精进·45天挑战·Day17
云朵大王
java 算法 leetcode
找出需要排序的最短子数组:一个高效的Java实现在数据结构与算法的学习中,我们经常遇到需要优化数组或列表的问题。今天,我们要探讨的是一个有趣且实用的挑战:给定一个整数数组,找出一个连续子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。我们的目标是找出这个符合题意的最短子数组,并输出它的长度。问题描述给定一个整数数组nums,我们需要找到一个最短的连续子数组,使得对这个子数组进行升
Java每日精进·45天挑战·Day19
云朵大王
java ios 开发语言
第一部分:移除数字以形成最小数的贪心算法实现在编程的世界里,我们经常遇到需要对字符串表示的数字进行操作的问题。今天,我们要深入探讨一个具体的挑战:给定一个以字符串形式表示的非负整数num和一个整数k,我们的任务是移除k位数字,以使得剩下的数字尽可能小。最终,我们需要返回这个最小的数字(仍然以字符串形式)。问题背景这个问题看似简单,实则充满了挑战。我们需要仔细思考如何高效地移除数字,以确保剩下的数字
观望=没有!
郭顺发_
博客 经验分享
“兄弟,Java现在学还有前途吗?”“前端是不是饱和了?”——每天打开私信,这类问题能占大半。我的回复永远只有一句:“如果你非要等我说‘行’才敢行动,那答案已经不重要了。”#技术人总在纠结“能不能”一直在等权威认证有人私信问“学Java还能找到工作吗”,自己却从来没打开过招聘网站——实际上,2024年Java岗位仍占后端需求的百分之四五十。考虑技术风向新手在Vue/React/Svelte之间反复
【HarmonyOS NEXT】异步编程的神器之Promise
androidios前端
1.背景异步编程对ArkTS这门语言来说实在太重要。因为ArkTS是单线程模型【单线程模型指的是,JavaScript只在一个线程上运行。也就是说,JavaScript同时只能执行一个任务,其他任务都必须在后面排队等待。】如果没有异步编程,很容易就写出回调地狱般的屎山代码。现在在ArkTS中要实现异步并发任务时,最合适的就是使用Promise和async/await【在此之前JS异步的发展历程是c
面试题之Vuex,sessionStorage,localStorage的区别
阿丽塔~
前端 javascript 开发语言
Vuex、localStorage和sessionStorage都是用于存储数据的技术,但它们在存储范围、存储方式、应用场景等方面存在显著区别。以下是它们的详细对比:1.存储范围Vuex:是Vue.js的状态管理库,用于存储全局状态。数据存储在内存中,页面刷新后数据会丢失。只在当前应用实例的生命周期内有效。localStorage:是浏览器提供的WebStorageAPI的一部分。数据存储在浏览器
基于微信小程序的电影院订票选座系统的设计与实现,SSM+Vue+毕业论文+开题报告+任务书+指导搭建视频
初尘屿风
Javaweb 毕业设计 初尘屿风 微信小程序 vue.js 小程序
本系统包含用户、管理员两个角色。用户角色:注册登录、查看首页电影信息推荐、查看电影详情并进行收藏预定、查看电影资讯、在线客服、管理个人订单等。管理员角色:登录后台、管理电影类型、管理放映厅信息、管理电影信息、管理用户信息、管理订单等。运行环境jdk8+mysql+IntelliJIDEA+maven3+微信开发者工具项目技术Spring+SpringMvc+Mybatis+html+css+js+
vue中多功能上传文件图片按钮二次封装
蚂蚁家的砖
封装 前端 vue vue.js javascript ecmascript
beforeFileUpload(file)":disabled="inlineFileList.length>=limit||disabled":on-preview="onPreview":show-file-list="false">=limit||disabled":type="type":plain="plain":size="size">{{name}}{{description}}{
python csv文件写入(推荐)
lxin_ooo
python csv python
python将数据写入到.csv文件里importjsonimportosimportcsvclassSaveCSV(object):defsave(self,keyword_list,path,item):try:#第一次打开文件时,第一行写入表头ifnotos.path.exists(path):withopen(path,"w",newline='',encoding='utf-8')asc
【php】php json_encode($arr) 和 json_encode($arr, 320) 有什么区别?
小镇学者
PHP php json 开发语言
在PHP中,json_encode()函数用于将PHP变量(通常是数组或对象)编码为JSON格式的字符串。json_encode($arr)和json_encode($arr,320)的区别主要在于第二个参数,该参数是一个由多个JSON_*常量按位或(|)组合而成的选项掩码,用于控制编码过程中的行为。1.json_encode($arr)当只传递一个参数时,即json_encode($arr),它
Java程序员面临抉择:激烈竞争下,转行大模型或是新出路,非常详细收藏我这一篇就够了!
大模型教程
大模型学习 学习 大模型 语言模型 人工智能 程序员 转行
Java程序员转行大模型领域,可以依据以下详细路线进行学习和职业转换:第1阶段:基础知识巩固数学基础:线性代数:矩阵运算、向量空间等。概率论与统计:概率分布、统计推断等。微积分:导数、积分、多变量函数等。Python编程:Python基础:数据类型、控制结构、函数等。Python进阶:面向对象编程、装饰器、生成器等。数据处理:NumPy、Pandas、Matplotlib。第2阶段:机器学习与深度
go 树形结构转为数组
zsd_666
Web前端 golang 算法 开发语言
go树形结构转为数组菜单结构体typeMenuItemstruct{IDint`json:"id"`ParentIDint`json:"parent_id"`Namestring`json:"name"`Children[]*MenuItem`json:"children,omitempty"`//子节点列表}树形菜单转数组funcTreeToArray(root*MenuItem)[]MenuI
Vue3 循环语句
wjs2024
开发语言
Vue3循环语句引言在Web开发中,循环语句是处理数据集合的常用手段。Vue3作为当下流行的前端框架,提供了丰富的循环语句,以帮助我们更高效地处理数据。本文将详细介绍Vue3中的循环语句,包括其使用方法、优缺点以及在实际项目中的应用。一、Vue3中的循环语句Vue3提供了三种循环语句,分别是v-for、v-if和v-else-if。下面将逐一介绍。1.1v-forv-for是Vue3中最常用的循环
Spring Boot:Java开发的神奇加速器(二)
小周不想卷
艾思科蓝学术会议投稿 spring boot
目录四、深入理解SpringBoot配置4.1配置文件类型4.2常用配置项4.3自定义配置五、数据访问与持久化5.1集成SpringDataJPA5.2编写数据访问层代码5.3事务管理四、深入理解SpringBoot配置4.1配置文件类型在SpringBoot应用中,主要有两种配置文件类型,即application.properties和application.yml(或application.y
Jenkins 拉取 Git 分支代码问题排查与解决指南
码农阿豪@新空间
包罗万象 疑难杂症解决方案 git 运维 jenkins
个人名片作者简介:java领域优质创作者个人主页:码农阿豪工作室:新空间代码工作室(提供各种软件服务)个人邮箱:[
[email protected] ]个人微信:15279484656个人导航网站:www.forff.top座右铭:总有人要赢。为什么不能是我呢?专栏导航:码农阿豪系列专栏导航面试专栏:收集了java相关高频面试题,面试实战总结️Spring5系列专栏:整理了Spring5重要知识点与
js小程序ios日期解析失败NAN兼容
wapchief
前端技术 javascript 开发语言 ecmascript
小程序中ios使用newDate()的时候,如果有“-”分隔符,将会解析失败如果日期过短也会解析失败,比如只有2022-08,年月这样也解析不出来,下面工具能解决上述问题,但是在手动创建字符串时间,建议使用2022/08/01,斜杠等方式,需要组件展示的时候再用工具转换format(date,fmt){if(typeofdate==='string'){//ios解析不出来年月2020-05if(
如何发起http的请求,在系统中集成
红豆和绿豆
java http 网络协议 网络
在Java中发起HTTP请求,有多种开源框架可供选择。以下是一些常用的开源框架及其特点:1.ApacheHttpClientApacheHttpClient是一个功能强大的HTTP客户端库,支持同步和异步请求,广泛用于各种Java应用。2.OkHttpOkHttp是一个高效的HTTP客户端,支持HTTP/2和WebSocket,具有自动重试和恢复功能。3.UniRestUniRest是一个简单易用
前端必知必会-Vue ‘beforeMount‘ 生命周期钩子
编程岁月
前端 vue.js javascript
文章目录'beforeMount'钩子总结‘beforeMount’钩子beforeMount生命周期钩子在组件挂载之前发生,也就是在组件添加到DOM之前。我们应该避免尝试从beforeMount生命周期钩子访问DOM元素,因为在组件挂载之前DOM元素是不可访问的。下面的示例显示我们目前无法访问组件中的DOM元素,CompOne.vue中的第11行不起作用,并在浏览器控制台中生成错误:示例Comp
创建全局异常处理器(Global Exception Processor)
易安杰
java 开发语言 jvm spring boot
先来了解一下什么是异常?在Java程序中,异常(Exception)是指在程序执行过程中发生的非正常情况,它打断了正常的指令流;Java中的异常处理是一种用于处理程序中错误和异常情况的一种机制。如上图所示异常主要分为两类,包括Error和Exception,两种异常有一个共同的父类是Throwable;在Exception中又分为RuntimeException(运行时异常)和CheckedExc
【LeetCode Hot100】除自身以外数组的乘积|左右乘积列表,Java实现!图解+代码,小白也能秒懂!
AllowM
算法hot100 leetcode java 算法
[LeetCodeHot100]除自身以外数组的乘积|左右乘积列表,Java实现!图解+代码,小白也能秒懂!✏️本文对应题目链接:除自身以外数组的乘积题目描述给你一个整数数组nums,返回数组answer,其中answer[i]等于nums中除nums[i]之外其余各元素的乘积。题目数据保证数组之中任意元素的全部前缀元素和后缀的乘积都在32位整数范围内。请不要使用除法,且在O(n)时间复杂度内完成
AGP 8.0 适配 ---- jvm target compatibility
zhuzhumouse
android java gradle
基础知识科普Android工程的GradleJDK,以及代码里面配置的jvmTarget有什么区别?这是两个完全不同的概念:GradleJDK:指的是用于运行Gradle构建系统的JavaDevelopmentKit版本。Gradle是Android项目的构建工具,它负责处理项目的编译、打包、依赖管理等任务。GradleJDK的选择决定了在构建过程中使用的Java版本。jvmTarget:是jav
Vue 中 MVVM、MVC 和 MVP 模式的区别
AC-PEACE
vue.js mvc 前端
1)MVC模式(Model-View-Conitroler):·Model:数据层,负责与数据库或远程服务器交互,存取和操作数据。·View:视图层,负责用户界面的呈现。它不包含任何业务逻辑,仅显示从Model获得的数据。·Controller:控制器层,协调Model和View,处理用户输入并更新Model和View.2)MVP模式(Model-View-Presenter):·Model:与M
Java取绝对值
web15085181368
java
在Java中可以使用Math.abs()方法来方便的进行绝对值计算,例如:intvalue=Math.abs(-90);System.out.println(value);//90publicstaticintabs(inta){return(a<0)?-a:a;}当输入的是正数的时候直接返回即可,当是负数的时候返回它的相反数即可。使用三目运算符可以使用一行代码就能做到。如果需要输入Double或
项目中 枚举与注解的结合使用
飞翔的马甲
java enum annotation
前言:版本兼容,一直是迭代开发头疼的事,最近新版本加上了支持新题型,如果新创建一份问卷包含了新题型,那旧版本客户端就不支持,如果新创建的问卷不包含新题型,那么新旧客户端都支持。这里面我们通过给问卷类型枚举增加自定义注解的方式完成。顺便巩固下枚举与注解。
一、枚举
1.在创建枚举类的时候,该类已继承java.lang.Enum类,所以自定义枚举类无法继承别的类,但可以实现接口。
【Scala十七】Scala核心十一:下划线_的用法
bit1129
scala
下划线_在Scala中广泛应用,_的基本含义是作为占位符使用。_在使用时是出问题非常多的地方,本文将不断完善_的使用场景以及所表达的含义
1. 在高阶函数中使用
scala> val list = List(-3,8,7,9)
list: List[Int] = List(-3, 8, 7, 9)
scala> list.filter(_ > 7)
r
web缓存基础:术语、http报头和缓存策略
dalan_123
Web
对于很多人来说,去访问某一个站点,若是该站点能够提供智能化的内容缓存来提高用户体验,那么最终该站点的访问者将络绎不绝。缓存或者对之前的请求临时存储,是http协议实现中最核心的内容分发策略之一。分发路径中的组件均可以缓存内容来加速后续的请求,这是受控于对该内容所声明的缓存策略。接下来将讨web内容缓存策略的基本概念,具体包括如如何选择缓存策略以保证互联网范围内的缓存能够正确处理的您的内容,并谈论下
crontab 问题
周凡杨
linux crontab unix
一: 0481-079 Reached a symbol that is not expected.
背景:
*/5 * * * * /usr/IBMIHS/rsync.sh
让tomcat支持2级域名共享session
g21121
session
tomcat默认情况下是不支持2级域名共享session的,所有有些情况下登陆后从主域名跳转到子域名会发生链接session不相同的情况,但是只需修改几处配置就可以了。
打开tomcat下conf下context.xml文件
找到Context标签,修改为如下内容
如果你的域名是www.test.com
<Context sessionCookiePath="/path&q
web报表工具FineReport常用函数的用法总结(数学和三角函数)
老A不折腾
Web finereport 总结
ABS
ABS(number):返回指定数字的绝对值。绝对值是指没有正负符号的数值。
Number:需要求出绝对值的任意实数。
示例:
ABS(-1.5)等于1.5。
ABS(0)等于0。
ABS(2.5)等于2.5。
ACOS
ACOS(number):返回指定数值的反余弦值。反余弦值为一个角度,返回角度以弧度形式表示。
Number:需要返回角
linux 启动java进程 sh文件
墙头上一根草
linux shell jar
#!/bin/bash
#初始化服务器的进程PId变量
user_pid=0;
robot_pid=0;
loadlort_pid=0;
gateway_pid=0;
#########
#检查相关服务器是否启动成功
#说明:
#使用JDK自带的JPS命令及grep命令组合,准确查找pid
#jps 加 l 参数,表示显示java的完整包路径
#使用awk,分割出pid
我的spring学习笔记5-如何使用ApplicationContext替换BeanFactory
aijuans
Spring 3 系列
如何使用ApplicationContext替换BeanFactory?
package onlyfun.caterpillar.device;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import
Linux 内存使用方法详细解析
annan211
linux 内存 Linux内存解析
来源 http://blog.jobbole.com/45748/
我是一名程序员,那么我在这里以一个程序员的角度来讲解Linux内存的使用。
一提到内存管理,我们头脑中闪出的两个概念,就是虚拟内存,与物理内存。这两个概念主要来自于linux内核的支持。
Linux在内存管理上份为两级,一级是线性区,类似于00c73000-00c88000,对应于虚拟内存,它实际上不占用
数据库的单表查询常用命令及使用方法(-)
百合不是茶
oracle 函数 单表查询
创建数据库;
--建表
create table bloguser(username varchar2(20),userage number(10),usersex char(2));
创建bloguser表,里面有三个字段
&nbs
多线程基础知识
bijian1013
java 多线程 thread java多线程
一.进程和线程
进程就是一个在内存中独立运行的程序,有自己的地址空间。如正在运行的写字板程序就是一个进程。
“多任务”:指操作系统能同时运行多个进程(程序)。如WINDOWS系统可以同时运行写字板程序、画图程序、WORD、Eclipse等。
线程:是进程内部单一的一个顺序控制流。
线程和进程
a. 每个进程都有独立的
fastjson简单使用实例
bijian1013
fastjson
一.简介
阿里巴巴fastjson是一个Java语言编写的高性能功能完善的JSON库。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是目前Java语言中最快的JSON库;包括“序列化”和“反序列化”两部分,它具备如下特征:
【RPC框架Burlap】Spring集成Burlap
bit1129
spring
Burlap和Hessian同属于codehaus的RPC调用框架,但是Burlap已经几年不更新,所以Spring在4.0里已经将Burlap的支持置为Deprecated,所以在选择RPC框架时,不应该考虑Burlap了。
这篇文章还是记录下Burlap的用法吧,主要是复制粘贴了Hessian与Spring集成一文,【RPC框架Hessian四】Hessian与Spring集成
【Mahout一】基于Mahout 命令参数含义
bit1129
Mahout
1. mahout seqdirectory
$ mahout seqdirectory
--input (-i) input Path to job input directory(原始文本文件).
--output (-o) output The directory pathna
linux使用flock文件锁解决脚本重复执行问题
ronin47
linux lock 重复执行
linux的crontab命令,可以定时执行操作,最小周期是每分钟执行一次。关于crontab实现每秒执行可参考我之前的文章《linux crontab 实现每秒执行》现在有个问题,如果设定了任务每分钟执行一次,但有可能一分钟内任务并没有执行完成,这时系统会再执行任务。导致两个相同的任务在执行。
例如:
<?
//
test
.php
java-74-数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字
bylijinnan
java
public class OcuppyMoreThanHalf {
/**
* Q74 数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字
* two solutions:
* 1.O(n)
* see <beauty of coding>--每次删除两个不同的数字,不改变数组的特性
* 2.O(nlogn)
* 排序。中间
linux 系统相关命令
candiio
linux
系统参数
cat /proc/cpuinfo cpu相关参数
cat /proc/meminfo 内存相关参数
cat /proc/loadavg 负载情况
性能参数
1)top
M:按内存使用排序
P:按CPU占用排序
1:显示各CPU的使用情况
k:kill进程
o:更多排序规则
回车:刷新数据
2)ulimit
ulimit -a:显示本用户的系统限制参
[经营与资产]保持独立性和稳定性对于软件开发的重要意义
comsci
软件开发
一个软件的架构从诞生到成熟,中间要经过很多次的修正和改造
如果在这个过程中,外界的其它行业的资本不断的介入这种软件架构的升级过程中
那么软件开发者原有的设计思想和开发路线
在CentOS5.5上编译OpenJDK6
Cwind
linux OpenJDK
几番周折终于在自己的CentOS5.5上编译成功了OpenJDK6,将编译过程和遇到的问题作一简要记录,备查。
0. OpenJDK介绍
OpenJDK是Sun(现Oracle)公司发布的基于GPL许可的Java平台的实现。其优点:
1、它的核心代码与同时期Sun(-> Oracle)的产品版基本上是一样的,血统纯正,不用担心性能问题,也基本上没什么兼容性问题;(代码上最主要的差异是
java乱码问题
dashuaifu
java乱码问题 js中文乱码
swfupload上传文件参数值为中文传递到后台接收中文乱码 在js中用setPostParams({"tag" : encodeURI( document.getElementByIdx_x("filetag").value,"utf-8")});
然后在servlet中String t
cygwin很多命令显示command not found的解决办法
dcj3sjt126com
cygwin
cygwin很多命令显示command not found的解决办法
修改cygwin.BAT文件如下
@echo off
D:
set CYGWIN=tty notitle glob
set PATH=%PATH%;d:\cygwin\bin;d:\cygwin\sbin;d:\cygwin\usr\bin;d:\cygwin\usr\sbin;d:\cygwin\us
[介绍]从 Yii 1.1 升级
dcj3sjt126com
PHP yii2
2.0 版框架是完全重写的,在 1.1 和 2.0 两个版本之间存在相当多差异。因此从 1.1 版升级并不像小版本间的跨越那么简单,通过本指南你将会了解两个版本间主要的不同之处。
如果你之前没有用过 Yii 1.1,可以跳过本章,直接从"入门篇"开始读起。
请注意,Yii 2.0 引入了很多本章并没有涉及到的新功能。强烈建议你通读整部权威指南来了解所有新特性。这样有可能会发
Linux SSH免登录配置总结
eksliang
ssh-keygen Linux SSH免登录认证 Linux SSH互信
转载请出自出处:http://eksliang.iteye.com/blog/2187265 一、原理
我们使用ssh-keygen在ServerA上生成私钥跟公钥,将生成的公钥拷贝到远程机器ServerB上后,就可以使用ssh命令无需密码登录到另外一台机器ServerB上。
生成公钥与私钥有两种加密方式,第一种是
手势滑动销毁Activity
gundumw100
android
老是效仿ios,做android的真悲催!
有需求:需要手势滑动销毁一个Activity
怎么办尼?自己写?
不用~,网上先问一下百度。
结果:
http://blog.csdn.net/xiaanming/article/details/20934541
首先将你需要的Activity继承SwipeBackActivity,它会在你的布局根目录新增一层SwipeBackLay
JavaScript变换表格边框颜色
ini
JavaScript html Web html5 css
效果查看:http://hovertree.com/texiao/js/2.htm代码如下,保存到HTML文件也可以查看效果:
<html>
<head>
<meta charset="utf-8">
<title>表格边框变换颜色代码-何问起</title>
</head>
<body&
Kafka Rest : Confluent
kane_xie
kafka REST confluent
最近拿到一个kafka rest的需求,但kafka暂时还没有提供rest api(应该是有在开发中,毕竟rest这么火),上网搜了一下,找到一个Confluent Platform,本文简单介绍一下安装。
这里插一句,给大家推荐一个九尾搜索,原名叫谷粉SOSO,不想fanqiang谷歌的可以用这个。以前在外企用谷歌用习惯了,出来之后用度娘搜技术问题,那匹配度简直感人。
环境声明:Ubu
Calender不是单例
men4661273
单例 Calender
在我们使用Calender的时候,使用过Calendar.getInstance()来获取一个日期类的对象,这种方式跟单例的获取方式一样,那么它到底是不是单例呢,如果是单例的话,一个对象修改内容之后,另外一个线程中的数据不久乱套了吗?从试验以及源码中可以得出,Calendar不是单例。
测试:
Calendar c1 =
线程内存和主内存之间联系
qifeifei
java thread
1, java多线程共享主内存中变量的时候,一共会经过几个阶段,
lock:将主内存中的变量锁定,为一个线程所独占。
unclock:将lock加的锁定解除,此时其它的线程可以有机会访问此变量。
read:将主内存中的变量值读到工作内存当中。
load:将read读取的值保存到工作内存中的变量副本中。
schedule和scheduleAtFixedRate
tangqi609567707
java timer schedule
原文地址:http://blog.csdn.net/weidan1121/article/details/527307
import java.util.Timer;import java.util.TimerTask;import java.util.Date;
/** * @author vincent */public class TimerTest {
erlang 部署
wudixiaotie
erlang
1.如果在启动节点的时候报这个错 :
{"init terminating in do_boot",{'cannot load',elf_format,get_files}}
则需要在reltool.config中加入
{app, hipe, [{incl_cond, exclude}]},
2.当generate时,遇到:
ERROR