2020.01-2020.12 AIZOO 可视化机器学习平台
项目介绍:实现用户自定义上传算法模型和数据资源,通过可视化界面拖拽组件构建模型,提交任务,使用 slurm 集群管理自动部署模型训练,查看训练结果以及分析图表等的一站式机器学习平台。
负责内容:
(1) 前端开发:采用 Vue 框架+iview 组件库,基于 WebSocket 即时通讯和 Echarts 图表库绘制动态折线图,通过 API 接口与 Java 后台交互。
(2) 可视化构建模型:使用 svg 绘图和 Cytoscape.js 图库, 通过拖拽(H5的原生拖拽事件)组件构建模型图。
前端主要是两个人, 后台有三个同学, 有两个负责java开发, 一个负责slurm集群管理
vue + Cytoscape.js
什么是multipart/form-data请求–https://www.cnblogs.com/tylerdonet/p/5722858.html
项目中使用截图:
大文件上传
断点续传
目前项目里的服务器合并文件是先建立一个临时目录存放上传的分片文件, 上传完成以后合并merge,再挪到项目存放路径下.
分片的临时文件存在服务器上, 最后合并请求以后挪到项目存放路径下.若用户量巨大, 服务器单点无法完成任务,需要扩容到多台服务器.
每个人访问服务器可以路由到不同服务器上, 分片成200个文件可能50个文件在服务器1上, 150个文件在服务器2上.
解决方案(蚂蚁二面面试官的解决方案):
1- 阿里云(爱sei爱思?)/亚马逊(s3?)等有一些专门做存储的云服务, 可以直接把文件存到云服务上面, 这样无论应用层扩展到多少层, 这样存储永远都是分布式的云存储, 就可以借用这种已经存在的标准的服务和接口来实现.
2- 通过一些方式把用户路由到一台服务器上, 确保用户所有的临时文件都存在一个服务器上,需要保证这一个用户同一时刻只在一个服务节点上. 但这种方案会把整个应用集群从无状态变成有状态,需要去感知当前我服务的是哪些用户以及用户在哪些机器上, 这样会导致比较高的复杂度.
实现一个大文件上传和断点续传- https://juejin.cn/post/6844904046436843527
针对上一个链接的扩展-https://juejin.cn/post/6844904055819468808#heading-8
大文件上传项目github地址-https://github.com/yeyan1996/file-upload
各种文件上传攻略,从小图片到大文件断点续传-https://juejin.cn/post/6844903968338870285
使用Html5的WebSocket在浏览器上传文件
文件上传的步骤: 打开websocket–连接websocket服务器–在浏览器里选择文件–将文件读入到内存中(以arraybuffer的形式)–在socket里发送文件–完毕!
服务器端:
配置好websocket的服务器, 使用一个java的开源websocket服务器: Java-WebSocket
根据该项目的快速教程可以建立一个websocket服务器, 就是里面的一个ChatServer.java文件. 一个聊天室服务器.
客户端(html): 先建立websocket连接, 然后使用new FileReader()
通过readAsArrayBuffer
以二进制形式读取文件
很好的参考链接websocket+HTTP2+grpc解析-https://ryan4yin.space/posts/websocket-http2-and-grpc/
// WebSocket API
var socket = new WebSocket('ws://websocket.example.com');
// Show a connected message when the WebSocket is opened.
socket.onopen = function(event) {
console.log('WebSocket is connected.');
};
// Handle messages sent by the server.
socket.onmessage = function(event) {
var message = event.data;
console.log(message);
};
// Handle any error that occurs.
socket.onerror = function(error) {
console.log('WebSocket Error: ' + error);
};
https://www.haorooms.com/post/long_lianjie_websocket
https://www.cnblogs.com/goody9807/p/4257192.html
https://www.cnblogs.com/goloving/p/9196066.html
https://my.oschina.net/u/4581713/blog/4594420
优势:
在不同的引擎上有不同的存储方式。
查询语句是使用传统的sql语句,拥有较为成熟的体系,成熟度很高。
开源数据库的份额在不断增加,mysql的份额页在持续增长。
缺点:
在海量数据处理的时候效率会显著变慢。
文档是mongoDB中数据的基本单元,类似关系数据库的行,多个键值对有序地放置在一起便是文档,语法有点类似javascript面向对象的查询语言,它是一个面向集合的,模式自由的文档型数据库。
存储方式:虚拟内存+持久化。
查询语句:是独特的Mongodb的查询方式。
适合场景:事件的记录,内容管理或者博客平台等等。
架构特点:可以通过副本集,以及分片来实现高可用。
数据处理:数据是存储在硬盘上的,只不过需要经常读取的数据会被加载到内存中,将数据存储在物理内存中,从而达到高速读写。
成熟度与广泛度:新兴数据库,成熟度较低,Nosql数据库中最为接近关系型数据库,比较完善的DB之一,适用人群不断在增长。
优点:
快速!在适量级的内存的Mongodb的性能是非常迅速的,它将热数据存储在物理内存中,使得热数据的读写变得十分快。高扩展性,存储的数据格式是json格式!
缺点:
不支持事务,而且开发文档不是很完全,完善。
1.如果需要将mongodb作为后端db来代替mysql使用,即这里mysql与mongodb 属于平行级别,那么,这样的使用可能有以下几种情况的考量:
(1)mongodb所负责部分以文档形式存储,能够有较好的代码亲和性,json格式的直接写入方便。(如日志之类)
(2)从datamodels设计阶段就将原子性考虑于其中,无需事务之类的辅助。开发用如nodejs之类的语言来进行开发,对开发比较方便。
(3)mongodb本身的failover机制,无需使用如MHA之类的方式实现。
2.将mongodb作为类似redis ,memcache来做缓存db,为mysql提供服务,或是后端日志收集分析。 考虑到mongodb属于nosql型数据库,sql语句与数据结构不如mysql那么亲和 ,也会有很多时候将mongodb做为辅助mysql而使用的类redis memcache 之类的缓存db来使用。 亦或是仅作日志收集分析。
博客园-https://www.cnblogs.com/sss4/p/8097653.html
海信空调报障系统采用了python-Flask 框架,使用 SQLAlchemy + Flask-SQLAlchemy 来控制数据库。
Python主流WEB框架对比
flask框架简单使用
from flask import Flask
app=Flask(__name__) #创建1个Flask实例
@app.route('/') #路由系统生成 视图对应url,1. decorator=app.route() 2. decorator(first_flask)
def first_flask(): #视图函数
return 'Hello World' #response
if __name__ == '__main__':
app.run() #启动socket
先问在项目里遇到的问题你是怎么解决的, 有什么方法, 比较方法的不同, 技术选型对比, 优缺点, 选择最适合的方法, 没有最好的方法只有最合适的方法, 了解差异以后才能更好的进行技术选型.
看解决问题时的思考和总结.
在开发方面的优势
与jquery对比:
jQuery是MVC模式即model,view,control,vue是MVVM模式,即model, view, ViewModel,
在性能方面的优势
数据驱动, 不会影响渲染, 整体更加流程
虚拟dom节点, 可以追踪依赖关系
vue源文档的解释
https://cn.vuejs.org/v2/guide/reactivity.html
vue.js 采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调
https://www.cnblogs.com/mlw1814011067/p/11283528.html
Proxy是 ES6 中新增的一个特性,翻译过来意思是"代理",用在这里表示由它来“代理”某些操作。 Proxy 让我们能够以简洁易懂的方式控制外部对对象的访问。其功能非常类似于设计模式中的代理模式。
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
使用 Proxy 的核心优点是可以交由它来处理一些非核心逻辑(如:读取或设置对象的某些属性前记录日志;设置对象的某些属性值前,需要验证;某些属性的访问控制等)。 从而可以让对象只需关注于核心逻辑,达到关注点分离,降低对象复杂度等目的。
https://www.cnblogs.com/gxp69/p/11325381.html
https://www.cnblogs.com/fs0196/p/12416187.html
https://www.cnblogs.com/wind-lanyan/p/9061684.html
作用:用唯一标识标记每一个节点,可以高效渲染虚拟DOM树, 默认用“就地复用”策略,方便了diff算法更高效的比对dom元素
使用v-for更新已渲染的元素列表时,默认用就地复用策略;列表数据修改的时候,他会根据key值去判断某个值是否修改,如果修改,则重新渲染这一项,否则复用之前的元素.
为什么设置key值
Vue 和 React 都实现了一套虚拟DOM,使我们可以不直接操作DOM元素,只操作数据便可以重新渲染页面, 其原理是Diff算法, 总体来说是指只会同级比较,不会跨级比较。
Vue 和 React 的虚拟DOM的Diff算法大致相同,其核心是基于两个简单的假设:
1.两个相同的组件产生类似的DOM结构,不同的组件产生不同的DOM结构。
2.同一层级的一组节点,他们可以通过唯一的id进行区分。
基于以上这两点假设,使得虚拟DOM的Diff算法的复杂度从O(n^3)降到了O(n)。
用一张图简单说明一下:
当页面的数据发生变化时,Diff算法只会比较同一层级的节点:
如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点。
如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新。
如上图:在同级A,B,C,D四个节点中,在B和C之间插入E,没有key的时候:C更新成了E,D更新成了C,最后插入D,这样效率很低。
加上key之后,就能准确的找到节点的位置:发现ABCD都没变化,直接插入E就可以了。
所以key的作用主要是为了唯一标识每个节点, 以能够高效的更新虚拟DOM
为什么不能用index作为key
例如一组数:
list:[
{
id: 1,
name: 'a',
//index: 0
},
{
id: 2,
name: 'b',
//index: 1
},
{
id: 3,
name: 'c',
//index: 2
},
{
id: 4,
name: 'd',
//index: 3
},
]
这样的页面显示的是:a,b,c,d(默认选中c)
如果key绑定的是index, 删掉index=1的第二组数(b),除了b之外,c和d的index变化了(c变为1了,d的变为2了),所以c和d也都要重新渲染一遍,影响了性能。
刚开始默认选中c(index原来为2),删除b后,d的index变为2了,这时候页面上默认就选中d了,这就产生了bug
掘金-instanceOf 和 typeof的原理
typeof 是一个操作符,其右侧跟一个一元表达式,并返回这个表达式的数据类型。返回的结果用该类型的字符串(全小写字母)形式表示,包括以下 7 种:number、boolean、symbol、string、object、undefined、function
instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。 instanceof 检测的是原型。
instanceof 主要的作用就是判断一个实例是否属于某种类型
let person = function () {
}
let nicole = new person()
nicole instanceof person // true
instanceof 也可以判断一个实例是否是其父类型或者祖先类型的实例。
let person = function () {
}
let programmer = function () {
}
programmer.prototype = new person()
let nicole = new programmer()
nicole instanceof person // true
nicole instanceof programmer // true
当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用。
比较准确的判断对象实例的类型时,可以采取 Object.prototype.toString.call
方法
toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。
对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。
Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call('hi') // "[object String]"
Object.prototype.toString.call({
a:'hi'}) // "[object Object]"
Object.prototype.toString.call([1,'a']) // "[object Array]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(() => {
}) // "[object Function]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"
1.callback
经过深层次的嵌套,会产生回调地狱,需手动检查err参数。
2.promise
通过链式调用,直接在 then
中返回一个 promise
来进行成功之后的回调函数,用 catch
来做错误处理。
3.async/await
是基于Promise
实现的,它不能用于普通的回调函数,直接将其变成了同步的写法,使得异步代码看起来像同步代码,既可以用.catch
又可以用try-catch
捕捉,简洁,可读性强,写法更加优雅 。
原文链接:https://blog.csdn.net/m0_48076809/article/details/106439990
掘金文章-浅谈Promise与async/await的区别
跨域请求
var obj = {
fn: function () {
console.log(this) // obj, function定义的函数, this指向调用环境
// obj.fn()返回了一个箭头函数, 所以下面调用时是obj.fn()()
return () => {
console.log(this); // obj, 箭头函数中的this,指向定义箭头函数时的环境
(function () {
console.log(this) })() // windows, 立即调用函数
setTimeout(function () {
console.log(this) }, 1) // windows
}
}
}
obj.fn()()
Whenever a function is called, we must look at the immediate left side of the brackets / parentheses “()”. If on the left side of the parentheses we can see a reference, then the value of “this” passed to the function call is exactly of which that object belongs to, otherwise it is the global object.
每当函数被调用时,我们必须查看方括号/圆括号()的左侧。
如果在括号左侧可以看到一个引用,那么传递给函数调用的this
的值就是该对象所属的值,否则它就是全局对象。
对于函数中的this
,通过查看()
左边所属的对象去确定,真的很好用。
而实质上,this
是在创建函数的执行环境时,在创建阶段确定的,因此,弄透执行环境,去思考执行环境创建阶段的this
的指向,this
的指向就不会弄错了吧。
在全局作用域/全局环境(global scope| global context
)中,this
指向的就是全局变量
在浏览器里,指向window
对象
在Node.js
里,指向global
对象
1.例一
在任何函数中,this
的指向都不是静态的(static
)。它总是在你调用一个函数,但尚未执行函数内部代码前被指定。(查看参考链接中的执行环境的文章,这个阶段,实际就是初始化变量对象,在初始化变量对象的时候,确定了this
的指向)
实际上,this
是 被调用的函数的父作用域 提供的,更重要的是,我们要看看函数调用时是怎么写的。
当一个函数被调用时,应该立马看函数名()
左边的部分。
如果()
左边是一个引用(reference),那么,函数的this
指向的就是这个引用所属的对象,否则this
指向的就是全局对象(window|global
)
2.例二
function bar() {
console.log(this);
}
bar(); // windows- because the method bar() belongs to the windows object when invoked
// 这里,this指向的是全局对象。我们先看()的左边,是bar, bar属于全局对象,所以this指向的就是全局对象。
var foo = {
baz: function() {
console.log(this);
}
}
foo.baz(); // foo - because the method baz() belongs to the object foo when invoked
// 这里,this指向的是foo,先看()左边是baz,baz属于foo,所以baz里的this指向的就是foo
var anum = 0;
var foo = {
anum: 10,
baz: {
anum: 20,
bar: function() {
console.log(this)
console.log(this.anum);
}
}
}
foo.baz.bar(); // 20 - because left side of () is bar, which belongs to baz object when invoked
// ()左边是bar,bar属于foo.baz,所以this就是foo.baz,因此this.anum = foo.baz.anum = 20
var hello = foo.baz.bar;
hello(); // 0 - because left side of () is hello, which belongs to global object when invoked
// ()左边是hello,hello属于全局对象,所以this指向全局对象,this.anum = window.anum = 0
5.例五
内部匿名函数无法直接访问外部函数的this
和arguments
, 在非严格模式下内部匿名函数的this
指向Window
, 严格模式下指向undefined
.
const obj = {
name: 'spike',
friends: ['deer', 'cat'],
loop: function() {
console.log(this); // 这个this指向obj
this.friends.forEach(
function( friend ) {
// 这个this指向Window
console.log(this);
console.log(`${
this.name} knows ${
friend}`);
}
)
}
}
obj.loop();
// ()左边是loop,属于obj,所以loop函数中的this指向obj
当使用new
关键字去执行构造函数时,构造函数中的this
指向的的就是新建的那个对象实例。
var savedThis;
function Constr() {
// 保存构造函数中的this
savedThis = this;
}
// 通过new关键字执行构造函数
var inst = new Constr();
// 构造函数中的this指向的就是新创建的对象实例inst
console.log(savedThis === inst); // true
如果没有用new
关键字去执行构造函数,那么就要分析函数被调用时所属的作用域了
function Point(x, y) {
this.x = x;
this.y = y;
}
var p = Point(7, 5); // 没有用new关键字去执行构造函数!
console.log(p === undefined); // 没有用new,所以构造函数没有返回一个实例对象, 所以p === undefined
// 没有用new关键字,Point(7,5);就只是把函数执行了一遍
// ()左边是Point,属于全局对象,所以this指向全局对象
console.log(x); // 7
console.log(y); // 5
<div id="test">I am an element with id #test</div>
function doAlert() {
alert(this.innerHTML);
}
doAlert(); // undefined
// doAlert()属于全局对象
var myElem = document.getElementById('test');
myElem.onclick = doAlert;
alert(myElem.onclick === doAlert); // true
myElem.onclick(); // I am an element
// ()左边是onclick也就是doAlert,属于myElem,所以this指向myElem
哪个元素触发事件,this
就指向那个元素