• 关于

    Ajax-同步和异步

    的搜索结果

问题

前端面试经典题目合集-Ajax 是什么?Ajax 的交互模型?同步和异步的区别?如何解决跨域问题?

前端面试经典题目合集-Ajax 是什么?Ajax 的交互模型?同步和异步的区别?如何解决跨域问题?...
小柯卡力多 2019-12-01 22:06:16 11 浏览量 回答数 1

回答

Ajax 是什么: 1. 通过异步模式,提升了用户体验 2. 优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占用 3. Ajax 在客户端运行,承担了一部分本来由服务器承担的工作,减少了大用户量下的服务器负载。 Ajax 的最大的特点: 1. Ajax可以实现动态不刷新(局部刷新) 2. readyState 属性 状态 有5个可取值: 0 = 未初始化,1 = 启动, 2 = 发送,3 = 接收,4 = 完成 Ajax 同步和异步的区别: 1. 同步:提交请求 -> 等待服务器处理 -> 处理完毕返回,这个期间客户端浏览器不能干任何事 2. 异步:请求通过事件触发 -> 服务器处理(这是浏览器仍然可以作其他事情)-> 处理完毕 ajax.open方法中,第3个参数是设同步或者异步。 Ajax 的缺点: 1. Ajax 不支持浏览器 back 按钮 2. 安全问题 Ajax 暴露了与服务器交互的细节 3. 对搜索引擎的支持比较弱 4. 破坏了程序的异常机制 5. 不容易调试 解决跨域问题: 1. jsonp 2. iframe 3. window.name、window.postMessage 4. 服务器上设置代理页面
小柯卡力多 2019-12-02 03:23:36 0 浏览量 回答数 0

回答

业务代码中有数据库事务锁,其实是卡在事务上了,或者是某个地方不恰当的使用了锁######回复 @malie0 : 打断点应该属于特殊情况,你直接Thread.sleep(5000L)并发测,再看看请求响应的顺序。######回复 @malie0 : debug看下,线程池是不是耗尽了######应该没用到事务锁,response后面的代码可以什么都不写,就一个systemout的打印输出,然后打个断点,后面的请求就会卡住######在reponse返回的代码后面接下来继续处理业务逻辑 什么意思?reponse写出流之后,继续使用线程?那这个线程不会返回给servlet容器的线程池,接下来的请求会被给线程池中其他的线程######回复 @gaomq : 但是只要执行了response的返回就能立刻返回给前台的,跟后台有没有执行完方法没关系,应该不需要用异步servlet######回复 @malie0 : reponse想先返回,需要开异步。一个request和response处理一次请求。######对啊,就是当前线程在返回response响应代码后继续在处理业务逻辑,按照道理后面的请求会用另一个线程去处理,但是卡住了,只有等到这个线程处理完了才会处理下一个请求######http1.1在一个连接上,前一个请求收到响应才会发起下一个请求,是串行的。比如:请求1-->响应1,然后请求2-->响应2。 浏览器对同一个域名能建立的连接是有数量限制的。 猜测你的两个请求走的是同一个连接。######回复 @gaomq : 查到了这个,你看看https://stackoverflow.com/questions/45583861/how-does-http2-solve-head-of-line-blocking-hol-issue#answer-45583977,有问题再交流。######回复 @gaomq :谢谢你的回复,我又想了想,“并且多个请求可以重叠进行”好像不行。假如请求1和2连续发出,服务器端请求1由线程1处理,请求2由线程2处理,线程2处理的快,先写出了响应(响应2的TCP包应该是在响应1的前面的,但我不确定),客户端应该是识别不出这个响应是请求1还是请求2的。你有没有文章佐证你的观点。我说的是串行的,是我从http1.1和http2区别上看到的。######http 1.1则可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求######这个有没有办法解决,让他们走不同的连接,前台ajax或者后台的servlet的配置?######应该是你前端的业务是串行执行的吧,后端单线程还是多线程都是可以自己配置的,不同的web层框架,配置的方式不同。######前端是在得到一个响应后才会触发另一个,但是对于后端来说应该两次响应要用不同的线程去处理,现在的情况感觉后端就是用了同一个线程在处理,所以出现了串行的问题######ajax不是可以设置是否异步处理,######ajax应该是异步的。就算是同步也不是导致我的问题的原因,因为ajax已经根据第一次返回的响应发起了第二次请求,后台是第二次请求发起后阻塞了。ajax的异步和同步只是前端要不要等待响应结果才做其他事情还是在请求没返回响应的时候还能执行其他代码######java servlet是多线程的,http1的ajax是阻塞的,也就是只有等到结果返回才能进行下次请求,http2的ajax才是真正的异步,http1、http2这个是刚好前几天在这里看到一篇博客。######但是我的问题是前端已经接收到第一次请求的响应才发起第二个请求,后端在第二个请求的时候阻塞了,我觉得跟前端应该已经没关系了######感觉像是AJAX没有开启异步处理吧。######请问这个问题解决了吗?请教下
kun坤 2020-05-30 14:36:49 0 浏览量 回答数 0

问题

spring cloud springboot 框架源码 activiti工作流 前后分离

代码介绍 ------------- 本框架为 :springcloud + Springboot 微服务\分布式 工作流 前后分离 + 跨域 版本 (权限控制到菜单和按钮) 后...
游客ydre72cd7ywew 2019-12-01 19:57:42 15 浏览量 回答数 0

问题

spring cloud springboot 框架源码 activiti工作流 前后分离

代码介绍 ------------- 本框架为 :springcloud + Springboot 微服务\分布式 工作流 前后分离 + 跨域 版本 (权限控制到菜单和按钮) 后...
游客q6uipubrszn5g 2019-12-01 19:56:47 21 浏览量 回答数 0

问题

springcloud vue.js 微服务分布式 前后分离 activiti工作流

代码介绍 ------------- 本框架为 :springcloud + Springboot 微服务\分布式 工作流 前后分离 + 跨域 版本 (权限控制到菜单和按钮) 后...
游客ydre72cd7ywew 2019-12-01 19:59:33 11 浏览量 回答数 0

问题

spring cloud 微服务 分布式 Activiti6 工作流 vue.js html

代码介绍 ------------- 本框架为 :springcloud + Springboot 微服务\分布式 工作流 前后分离 + 跨域 版本 (权限控制到菜单和按钮) 后...
游客ydre72cd7ywew 2019-12-01 21:49:22 8 浏览量 回答数 0

问题

springcloud 项目源码 Activiti6 工作 微服务 分布式 vue.js html

代码介绍 ------------- 本框架为 :springcloud + Springboot 微服务\分布式 工作流 前后分离 + 跨域 版本 (权限控制到菜单和按钮) 后...
游客ydre72cd7ywew 2019-12-01 19:54:54 22 浏览量 回答数 0

问题

springcloud 微服务 分布式 Activiti6 工作流 vue.js html 项目源码

代码介绍 ------------- 本框架为 :springcloud + Springboot 微服务\分布式 工作流 前后分离 + 跨域 版本 (权限控制到菜单和按钮) 后...
游客ydre72cd7ywew 2019-12-01 20:00:15 13 浏览量 回答数 0

问题

springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html

代码介绍 ------------- 本框架为 :springcloud + Springboot 微服务\分布式 工作流 前后分离 + 跨域 版本 (权限控制到菜单和按钮) 后...
游客egqjd4t7mlyom 2019-12-01 19:58:16 35 浏览量 回答数 0

问题

springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html

代码介绍 ------------- 本框架为 :springcloud + Springboot 微服务\分布式 工作流 前后分离 + 跨域 版本 (权限控制到菜单和按钮) 后...
游客ydre72cd7ywew 2019-12-01 19:52:32 34 浏览量 回答数 0

问题

springcloud vue activiti工作流 前后分离 集成代码生成器 微服务分布式

代码介绍 ------------- 本框架为 :springcloud + Springboot 微服务\分布式 工作流 前后分离 + 跨域 版本 (权限控制到菜单和按钮) 后...
游客q6uipubrszn5g 2019-12-01 19:55:22 6917 浏览量 回答数 8

问题

springcloud 微服务分布式 vue activiti工作流 前后分离 集成代码生成器

代码介绍 ------------- 本框架为 :springcloud + Springboot 微服务\分布式 工作流 前后分离 + 跨域 版本 (权限控制到菜单和按钮) 后...
游客egqjd4t7mlyom 2019-12-01 19:53:36 191 浏览量 回答数 1

问题

spring cloud 微服务分布式 vue.js html 前后分离 集成代码生成器 shiro

代码介绍 ------------- 本框架为 :springcloud + Springboot 微服务\分布式 工作流 前后分离 + 跨域 版本 (权限控制到菜单和按钮) 后...
游客ydre72cd7ywew 2019-12-01 19:51:28 66 浏览量 回答数 0

问题

前端面试经典题目合集

本专题选取了前端面试易考知识点,旨在帮助大家加深对前端知识点的理解,进行复习备考准备。资料来源于网络,原作者@markyun(https://github.com/markyun/My-bl...
小柯卡力多 2019-12-01 22:06:33 14 浏览量 回答数 0

回答

1. 回调函数(callback) setTimeout(() => { // callback 函数体 }, 1000) 缺点:回调地狱,不能用 try catch 捕获错误,不能 return 回调地狱的根本问题在于: 缺乏顺序性: 回调地狱导致的调试困难,和大脑的思维方式不符嵌套函数存在耦合性,一旦有所改动,就会牵一发而动全身,即(控制反转)嵌套函数过多的多话,很难处理错误 ajax('XXX1', () => { // callback 函数体 ajax('XXX2', () => { // callback 函数体 ajax('XXX3', () => { // callback 函数体 }) }) }) 优点:解决了同步的问题(只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。) 2. Promise Promise就是为了解决callback的问题而产生的。 Promise 实现了链式调用,也就是说每次 then 后返回的都是一个全新 Promise,如果我们在 then 中 return ,return 的结果会被 Promise.resolve() 包装 优点:解决了回调地狱的问题 ajax('XXX1') .then(res => { // 操作逻辑 return ajax('XXX2') }).then(res => { // 操作逻辑 return ajax('XXX3') }).then(res => { // 操作逻辑 }) 缺点:无法取消 Promise ,错误需要通过回调函数来捕获 3. Generator 特点:可以控制函数的执行,可以配合 co 函数库使用 function *fetch() { yield ajax('XXX1', () => {}) yield ajax('XXX2', () => {}) yield ajax('XXX3', () => {}) } let it = fetch() let result1 = it.next() let result2 = it.next() let result3 = it.next() 4. Async/await async、await 是异步的终极解决方案 优点是:代码清晰,不用像 Promise 写一大堆 then 链,处理了回调地狱的问题 缺点:await 将异步代码改造成同步代码,如果多个异步操作没有依赖性而使用 await 会导致性能上的降低。 async function test() { // 以下代码没有依赖性的话,完全可以使用 Promise.all 的方式 // 如果有依赖性的话,其实就是解决回调地狱的例子了 await fetch('XXX1') await fetch('XXX2') await fetch('XXX3') } 下面来看一个使用 await 的例子: let a = 0 let b = async () => { a = a + await 10 console.log('2', a) // -> '2' 10 } b() a++ console.log('1', a) // -> '1' 1 对于以上代码你可能会有疑惑,让我来解释下原因 - 首先函数 b 先执行,在执行到 await 10 之前变量 a 还是 0,因为 await 内部实现了 generator ,generator 会保留堆栈中东西,所以这时候 a = 0 被保存了下来 - 因为 await 是异步操作,后来的表达式不返回 Promise 的话,就会包装成 Promise.reslove(返回值),然后会去执行函数外的同步代码 - 同步代码执行完毕后开始执行异步代码,将保存下来的值拿出来使用,这时候 a = 0 + 10 上述解释中提到了 await 内部实现了 generator,其实 await 就是 generator 加上 Promise的语法糖,且内部实现了自动执行 generator。如果你熟悉 co 的话,其实自己就可以实现这样的语法糖。
九旬 2020-05-24 22:21:06 0 浏览量 回答数 0

问题

Vue面试题汇总【精品问答】

是一套用于构建用户界面的渐进式JavaScript框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,方便与第三方库或既有项目整合。 从0到1自己构架一个vue项目...
问问小秘 2020-05-25 18:02:28 20475 浏览量 回答数 4

回答

在2.0版本更新的时候,echarts的各种图表操作方法,都依赖于option的设置,没有setOption,clear或者resize等方法都会报错直接导致异常, 2.0.1已经修复了。至于数据更新的问题,没必要使用clear的,我之前也是这么做,跟林峰沟通后,他提示我看了setOption方法的第二个参数设置为true,就可以了。回复 @fengzhiguan:我遇到跟您一样的问题,需要缩放才行,不知道您解决么?回复 @democracy:为什么我在setOption后面加了true还是不行。。。IE8上面回复 @fengzhiguan:我饼图在IE8缩小了,在火狐正常,你的解决了吗?我现在用的就是2.01,你的意思是不用2.01版本么?回复 @黄小明186211:没有解决,没有更新2.0.1,只采用了2.0版本说了老半天。。。还是没解决IE8兼容问题啊,我看2.0.1版本上面针对IE8也是有问题的(具体问题为:显示空白,但是IE8浏览器用放大缩小功能后能正常显示)解决了么这个问题,请教一下,我也遇到你的这个情况,不知道怎么解决您解决了么这个问题?我相信大多数人都发现2.0.1对IE8不兼容,这里我推荐大家使用echarts1.4.1可以完美兼容,而且功能都很齐全,操作也一样 setOption方法的第二个参数设置为true 怎么弄??????? @NeoCD你那边的IE8兼容问题,解决了吗?我测试了一下,官网的demo在IE8下都出不来,如果用IE8以上的浏览器,使用兼容模式,只要文档模式不是IE9,同样也出不来,将setOption的第二个参数设置为true,还是如此。mychart.setoption(option,true) 通过把 animation设置为false和把 setOption方法的第二个参数设置为true还不能解决此问题的,可以通过ajax去请求url,然后通过 setTimeout来处理,具体可以参考下这个例子 http://www.daimahome.com/echarts-zai-ie8-xia-bu-xian-shi-tu-biao.html 博主,这个图在ie8显示不了 这个应该是用了Canvas了吧。基本上canvas是不对IE8及以下兼容了的。回复 @梦幻女侠:没有,不知道这种动态地图是不是不兼容ie8,一般的地图能在ie8显示(交个朋友么QQ:844146928)您好,我也遇到这样的问题,您解决了么问题解决了么?我也遇到这个问题了我是动态获取数据会出现在IE8界面空白,界面缩放之后显示,后来尝试静态数据可以,于是去掉数据获得的时候同步,IE8出现效果了,可能是数据同步或者异步的问题,不清楚这对你有没帮助。蛮试试。我也在学。 IE毒瘤   setTimeout(function( xxxxxxxxxxxxxxxxx ),100) 这样可以解决 IE8就不要调试le,IE8真的的是各种坑,现在你看IE8调试完,IE9,IE10,IE11都不一样可以用
爱吃鱼的程序员 2020-06-15 19:42:46 0 浏览量 回答数 0

回答

真正的问题不在于“怎么赋给外面用”,而是“何时外面才能用”。为了理解这一点,你得明白什么是 async programming(异步编程),看这个虚构例子: var outside // 0. 我在外面 $.getJSON('/some/api/endpoint', function(response) { outside = response // 1. 你当然可以把响应数据赋值给外面的代码 }) console.log(outside) // 2. 但是你没法保证接下来的代码能正确运行 // 因为以上代码的运行顺序是 0 -> 2 -> 1从 0 到 2,代码是自上而下同步运行的,然而 1(注意:1 是 $.getJSON 的回调函数而不是 $.getJSON 方法本身)是在之后运行的,并且确切的时间无法预知,它取决于对于 '/some/api/endpoint' 的请求何时返回。所以上面的虚拟例子从语法上来说没有任何问题,你只是无法保证它能运行出期望的结果罢了(在现实中由于 event loop 的机制,1 总是晚于 2 运行的)。 So,我们不知道何时异步回调会执行(只知道它晚于同步代码),那我们怎么办?幸运的是我们知道:“反正它会运行的”(除非请求失败,然而那属于错误处理或异常处理的部分,此处我们只谈 happy path),所以我们就告诉它:“当它运行时该做什么”就是了。所以之前的例子可以改写一下: var outside $.getJSON('/some/api/endpoint', function(response) { outside = response // 你还是可以把响应数据赋值给外面的代码 console.log(outside) // 然后再执行相应的逻辑,因为这里面是同步的,你能保证顺序 }) 当然这个例子太简单了,以至于 outside 这个变量根本就是个摆设(who cares),领会精神就好。当然在实际中,由于代码组织的关系,我们不总是能把逻辑上的顺序按照线性的方式自上而下的写代码,不过没关系只要你心中始终拎清楚现在正在写的代码将在何时运行就好。举例而言,稍微改动一下上面的例子: var outside // 我不知道什么时候,但终将在某一时刻我要打印出 outside 的值 // 至于这个值是什么就看到时候是谁传 response 进来了 // 注意:这也同时暗示着,此函数的调用者一定要传递一个 response 进来,否则接下来的代码无意义 function printOutside(response) { outside = response console.log(outside) } // ... // 接着在未来的某个时候,某个请求调用了 printOutside 函数,outside 被顺利赋值并打印$.getJSON('/some/api/endpoint', printOutside)实际上,最后的 $.getJSON 写在 printOutside 的前面或后面都无所谓,它总是能正确运行的,因为无论写前写后,同步代码的解释执行都会先于 printOutside 被调用。而作为函数声明 $.getJSON 也总是能找到正确的 printOutside 函数(hoisting)。 这就是你想知道的“怎样给外面用”的最核心的知识,我尽可能通俗的讲解了。不过现实中会有非常多复杂的情形,比如最常见的:“异步回调里面再异步请求回调再异步请求回调再……”,也就是俗称的“回调地狱”——就需要更复杂一些的手段来让它们乖乖听话。这些进阶的知识其实并不难,只是在我之前描述的概念之上更进一步罢了。 那么最后我在给你点明一下如何在这个概念上进阶一步。想想看如果你是 jQuery 的作者(或者其他类似异步请求函数的作者),你要如何定义 $.getJSON 这个函数?重点是:你如何赋予使用者自由定义回调函数,然后你能确保它正确运行?先自己想想,然后看下面的伪代码: // 这里,我要定义这个 getJSON;本质上,它是对一个 xhr 请求的封装 $.prototype.getJSON = function(path, callback) { // 使用者需要告诉我两个条件:1,请求的 path;2,请求返回后要执行的 callback // 接着我开始封装 xhr 请求,具体的代码请参考 javascript 的 API 手册 // 比如这里:https://developer.mozilla.org/en-US/docs/AJAX/Getting_Started var xhr = new XMLHttpRequest() // 初始化一个 xhr 对象 xhr.onreadystatechange = function() { // xhr 请求发出后会有多种状态变化(根据请求的发送及接受情况),这个函数用于处理各种状况 // 因此真实的代码这里会比较复杂,然而最终一切 OK 的话我们能获得正确的 response // 要注意的是,此函数必须在 send 之前定义,否则 send 完之后 xhr 对象并不知道该继续做什么 // 这也就暗示着,onreadystatechange 其实是 send 在某一时刻调用的 // 这与前面的 printOutside 的例子有异曲同工之妙 // 拿到 response 之后我们开始调用 callback,并把 response 传递进去 callback(xhr.responseText) } xhr.open('GET', path) // 配置 xhr 的请求参数 xhr.send() // 发送真正的请求 } 真正的 jQuery 自然要比这个伪代码例子复杂多了(就连 xhr 的封装都不是在这里做的,我没记错的话 jQuery 还有更底层的函数,$.ajax?),它要处理的问题可不仅仅是调用 callback 这么简单,不过一旦你从作者角度明确了 callback 是如何被调用的,那么从使用者的角度来考量该如何利用 callback 就变得自然而然毫无窒碍了,这也就是常说的“知其然并知其所以然”。 有心的话,再研究一个举一反三的小题目吧(不难),研究明白了就能再上一个台阶。题目如下: 我们已经了解了这样的写法和用法: $.getJSON('some/api/endpoint', function(response) { // do something... }) 那么这样的写法和用法又是怎么实现的呢? $.getJSON('some/api/endpoint'[, maybeSomeAdditionalParams]) .success(function(response) { // do something when request is OK }) .fail(function(error) { // do something when it is NOT OK }) 一旦你掌握了这类写法是如何定义的,你就 get 到了新的姿势来处理可能存在的异步回调嵌套问题,并且这也是接下来你去学习更先进的异步编程范式的基础(比如 promises 等)。GL!
小旋风柴进 2019-12-02 02:22:52 0 浏览量 回答数 0

回答

1、jsonp必须遵循一个固定的格式。即请求的URL的search中必须存在一个jsonpcallback=functionName;响应的格式为functionName(/ json data /); 原理就是利用script不受同源策略限制的特点。2、在server返回数据之后,尽量删掉这个script。因为页面中有n多个jsonp,就会有n多个生成的script标签。造成dom臃肿。并且别人也可以通过观察html来指导你jsonp的请求细节。3、是看重写的mimeType是不是和server返回的一样。如果一样就没必要重写mimeType了。除此之外还用了setRequestHeader、overriderMimeType、abort等方法。4、看代码流程即可。我写了一个简单点的例子 (function (global) { // 防止低版本ie里,undefined被重写 var undefined = void(0); // 定义命名空间 var namespace = {}; // 默认的参数列表 var defaultOptions = { // ajax请求的路径是什么 url: '', // 往服务器发送的数据 data: '', // 使用什么http方法 type: 'get', // ajax请求方式,同步还是异步。默认为异步 async: true, // 成功时执行的函数 success: function (data) { }, // 失败时执行的函数 error: function (errInfo) { }, // 自定义请求首部列表 header: {}, // 重写的mimeType overrideMimeType: '', // 是否走缓存 cache: false, // 超时毫秒数。默认为0 表示不执行超时逻辑 timeout: 0, // 是否格式化参数为uri string processData: true, // 请求的mime类型 默认为表单提交 contentType: 'application/x-www-form-urlencoded', // 返回的数据格式 text|json dataType: 'text' }; /** * CORE * @param {Object} options 用户输入的参数 * @throw TypeError */ var ajax = function (options) { // 判断参数是否为对象,如果不是则抛出类型错误 if (!tool.isObject(options)) { throw new TypeError('参数类型错误'); } // 合并用户输入的参数列表和默认的参数列表 返回一个全新的参数列表对象 var userOptions = tool.extend(defaultOptions, options); // ajax第一步:获取ajax对象 var xhr = tool.getXHR(); // 1、如果是get系 需要把data拼接到url后面 if (/^(get|delete|head)$/img.test(userOptions.type)) { var data = tool.encodeToURIString(userOptions.data); userOptions.url = tool.hasSearch(userOptions.url, data); // 因为get系不需要传send参数,所以设置为null userOptions.data = null; } // 2、是否走缓存,如果不走缓存则在url后面加一个随机数来防止缓存 if (userOptions.cache === false) { // 因为search是有固定格式的 key=value 如果只写一个value是不合法的,所以必须构造一个key,而且这个key不能和已有的key重复 var random = '_=' + (Math.random() * 0xffffff).toFixed(0); userOptions.url = tool.hasSearch(userOptions.url, random); } // ajax操作第二步 xhr.open(userOptions.type, userOptions.url, userOptions.async); // 2.1 设置自定义请求首部信息 if (userOptions.header && tool.isObject(userOptions.header)) { tool.eachObject(userOptions.header, function (key, value) { xhr.setRequestHeader(key, value); }) } // 2.2 设置content-type http里表现mimeType的字段就是content-type // 设置请求的mimeType if (userOptions.contentType && tool.isString(userOptions.contentType)) { xhr.setRequestHeader('content-type', userOptions.contentType); } // 2.3 设置重写的mime类型 // 设置响应的mimeType if (userOptions.overrideMimeType && tool.isString(userOptions.overrideMimeType)) { xhr.overrideMimeType(userOptions.overrideMimeType); } // 2.4 判断是否执行超时逻辑 if (tool.isNumber(userOptions.timeout) && userOptions.timeout > 0) { xhr.timeout = userOptions.timeout; // 标准浏览器 if ('ontimeout' in xhr) { xhr.ontimeout = function () { userOptions.error('timeout'); } } else { // 低版本ie setTimeout(function () { // http的事务是否还没有完成 if (xhr.readyState !== 4) { // 强制终止http事务 xhr.abort(); } }, xhr.timeout); } } // 2.5 是否需要处理给服务器发送的数据,判断processData是否为true // 当给服务器发送的数据为二进制或者formData的时候,不需要处理这个数据 // 要把processData设置为false if (/^(post|put)$/igm.test(userOptions.type) && userOptions.processData === true) { userOptions.data = tool.encodeToURIString(userOptions.data); } // ajax第三步:接收响应 xhr.onreadystatechange = function () { // http的事务是否完成 if (xhr.readyState === 4) { // 获取响应主体 var responseText = xhr.responseText; // 判断状态码是否成功 if (/^2\d{2}$/.test(xhr.status)) { // 判断是否需要把响应主体格式化为json对象 if (userOptions.dataType === 'json') { // 因为不合法的json字符串无法转换为json对象,会出异常 try { responseText = tool.JSONParse(responseText); } catch (ex) { userOptions.error(ex); return; } } userOptions.success(responseText); // R如果响应码是错误的类型 } else if (/^(4|5)\d{2}$/.test(xhr.status)) { // 直接执行error userOptions.error(xhr.status); } } }; // ajax第四步:发送 xhr.send(userOptions.data); }; /** * 利用闭包,实现获取数据类型 * @param {string} type 数据类型 * @returns {Function} */ var getType = function (type) { return function (obj) { // 为什么要用Object.prototype.toString来判断类型? return Object.prototype.toString.call(obj) === '[object ' + type + ']'; } }; var tool = { /** * 利用惰性函数,实现获取ajax对象的方法 */ getXHR: (function () { var list = [function () { return new XMLHttpRequest; }, function () { return new ActiveXObject('Microsoft.XMLHTTP'); }, function () { return new ActiveXObject("Msxml2.XMLHTTP"); }, function () { return new ActiveXObject("Msxml3.XMLHTTP"); }]; var len = list.length; var xhr = null; while (len--) { try { list[len](); xhr = list[len]; break; } catch (ex) { continue; } } if (xhr !== null) { return xhr; } throw new Error('当前浏览器不支持此方法'); })(), /** * 合并多个对象 * @returns {{}} 合并后的对象 */ extend: function () { // 因为参数长度不固定,所以把参数列表转成数组 // var params = [].slice.call(arguments, 0); var voidObj = {}; this.each(arguments, function (item) { // item为每一个参数对象 tool.eachObject(item, function (key, value) { voidObj[key] = value; }); }); return voidObj; }, /** * 循环帮助函数,利用惰性函数 */ each: (function () { if ([].forEach) { return function (list, callback, context) { [].forEach.call(list, callback, context); } } return function (list, callback, context) { for (var i = 0, j = list.length; i < j; i++) { callback.call(context, list[i], i, list); } } })(), /** * 循环对象 * @param {Object} obj 要循环的对象 * @param {Function} callback 回调函数 * @param {Object|undefined} context 回调函数里头的上下文对象 */ eachObject: function (obj, callback, context) { for (var n in obj) { if (!obj.hasOwnProperty(n)) continue; callback.call(context, n, obj[n]); } }, /** * 给tool动态添加判断数据类型的方法 */ init: function () { this.each(['Object', 'Function', 'Array', 'String', 'Number'], function (item) { tool['is' + item] = getType(item); }) }, /** * 把一个对象格式化为uri string * @param {*} data 需要格式化的数据 * @return {string} 格式化之后得到的uri string */ encodeToURIString: function (data) { if (this.isString(data)) return data; if (!this.isObject(data)) return ''; var arr = []; this.eachObject(data, function (key, value) { arr.push(encodeURIComponent(key) + '=' + encodeURIComponent(value)); }); return arr.join('&'); }, /** * 往url后面拼接参数的方法 * @param {string} url url * @param {string} padString 要拼接的参数 * @returns {string} 拼接之后的url */ hasSearch: function (url, padString) { if (!padString) return url; // 如果有问号,说明url里已经有参数了,因为参数和参数之间用&来分隔 /*if (/\?/.test(url)) { return url + '&' + padString; } else { return url + '?' + padString; }*/ return url + (/\?/.test(url) ? '&' : '?') + padString; }, /** * 把json字符串格式化为json对象 * @param {string} jsonString json字符串 * @return {Object} json对象 */ JSONParse: function (jsonString) { if (window.JSON) { return JSON.parse(jsonString) } return eval('(' + jsonString + ')'); } }; tool.init(); // 把ajax方法放入命名空间中 namespace.ajax = ajax; tool.each(['get', 'post'], function (item) { /** * 动态添加get和post方法 * @param {string} url 请求的url * @param {Object} data 往服务器发送的数据 * @param {Function} callback 成功的回调函数 * @param {string} dataType 数据格式 */ namespace[item] = function (url, data, callback, dataType) { ajax({ url: url, type: item, data: data, success: callback, dataType: dataType }); } }); // 先把全局里已经存在的x先放到一边 var globalX = global.x; /** * 解决全局变量名冲突 * @param {string|undefined} symbol 更改的全局变量名 * @returns {Object} */ namespace.noConflict = function (symbol) { if (symbol && tool.isString(symbol)) { window[symbol] = namespace; } global!==undefined&&(window.x = globalX); return namespace; }; // 暴露到全局环境中 global.x = namespace; })(this); 用法和jquery的一样。不过我暴露的是x变量,不是$.
小旋风柴进 2019-12-02 02:28:33 0 浏览量 回答数 0

回答

结贴:这个问题解决了,在Extjs4.0中已经有此属性的配置了,看下面代码: Ext.Ajax.request( {                     method : 'POST',                     url : fields[i].js,                     async : false,//添加该属性即可同步                     success : function(response, option) {                         jsStr += response.responseText;                     },                     failure : function(response, option) {                         Ext.MessageBox.alert('错误信息提示',                                 '加载页面超时 或 页面连接错误!');                     }                 }); ######request是异步的啊 ,跟我当年的困惑一样,折腾了好久才明白……哈哈 ###### 引用来自“天涯咫尺”的答案 jquery ajax里面有个参数asycn 默认是true 代表异步,你把它设置成false时,就可用用了。 ext里面应该也有,因为这是ajax的一个参数。 asycn 表示的意思是单个ajax请求的时候 是否为异步, 如果设置为false, 则要等到服务器返回才会继续往下执行代码, 也就是你的页面就卡那, 直到服务器返回. 对于多个ajax之间的同步没有用处. 设置为false后, 每发送一个请求就卡住, 直到他返回, 每次返回都会触发success或failure, 而不是同步所有的ajax都完成之后, 只触发一次success或failure. ######你说的完全对,不过ajax的同步有时也是有用的。必须说在等待后台返回的数据,然后判断进行操作,最后返回TRUE或者FALSE的时候,必须要用ajax的同步了,或者能提供一个别的思路###### 引用来自“szmneo”的答案 request是异步的啊 ,跟我当年的困惑一样,折腾了好久才明白……哈哈 我也发现这个问题了,可是如何解决呢? 真是头疼 ######难道你知道原因了还搞不定ext的同步请求吗?extjs3.2是要自己另加插件的,叫ext-basex.js,然后代码里Ext.Ajax.request里就可以用async : false来控制,4.0我还没开始用呢,不知道内置async了没,自己查看源码吧###### 引用来自“Panaon”的答案 引用来自“szmneo”的答案 request是异步的啊 ,跟我当年的困惑一样,折腾了好久才明白……哈哈 我也发现这个问题了,可是如何解决呢? 真是头疼 那就在ajax的回调函数里面alert呗,或者在回调函数里面调用一个函数,这个函数做alert. ######ajax应该有支持同步的吧,看看是否有同步的参数,jquery是支持的###### jsStr变量在function里面赋的值,以上那种情况外面的jsStr肯定是没有值的。######楼主, 你的意图没有说明白, 你是希望在所有的返回字符串全部链接完毕后再弹出对话框吗? 如果是这样, 你应该使用回调, 而不是return返回结果. 因此必须有一个外部的甚至是全局的变量用来存储返回的值, 并在回调中进行计数, 当全部响应后, 即计数等于循环最大值后, 才调用弹出.  var res= {sum:0,ary:[]};//make sure accessible in your scope var handleFn = function(success, msg, max){     if (success) res.ary.push(msg);    if (max == ++res.sum) alert(res.ary.join(''));//all responsed, call your function back } 在ajax的success方法中改为 handleFn(true, response.responseText, fields.length); 同理,在failure方法中改为 handleFn(false, response.responseText, fields.length); 当所有的请求全部响应时, 才调用你定义的方法, 此处是alert. ######和 extjs 没啥关系 去掉 extjs 代码 , 剩下 var jsFieldLoading = function(fields) {                 var jsStr = "";                                 alert("test:" + jsStr);                 return jsStr;                   } jsFieldLoading只是一个变量, 当然不会 alert , 如果想 alert , 加一个括号就行了。   var jsFieldLoading = function(fields) {                 var jsStr = "";                                 alert("test:" + jsStr);                 return jsStr;                   }();    ######你这真会误导 人……###### 引用来自“scl33”的答案 楼主, 你的意图没有说明白, 你是希望在所有的返回字符串全部链接完毕后再弹出对话框吗? 如果是这样, 你应该使用回调, 而不是return返回结果. 因此必须有一个外部的甚至是全局的变量用来存储返回的值, 并在回调中进行计数, 当全部响应后, 即计数等于循环最大值后, 才调用弹出.  var res= {sum:0,ary:[]};//make sure  accessible in your scope var handleFn = function(success, msg, max){     if (success) res.ary.push(msg);    if (max == ++res.sum) alert(res.ary.join(''));//all responsed, call your function back } 在ajax的success方法中改为 handleFn(true, response.responseText, fields.length); 同理,在failure方法中改为 handleFn(false, response.responseText, fields.length); 当所有的请求全部响应时, 才调用你定义的方法, 此处是alert. 这个功能主要响应EXTJS treepanel点击事件,加载指定URL的页面,因为用到了tabPanel所以对于使用全局变量不合适,而对于在success后执行自定义方法,并不能确定我调用jsFieldLoading方法是返回的是有效的值,现在问题困在如何返回AJAX请求到的文件内容,对于Extjs4.0里没有找到Ext.Ajax的同步设置属性,我现在想不出更好的方案解决它。
kun坤 2020-06-08 10:57:40 0 浏览量 回答数 0

问题

程序员报错QA大分享(1)

程序员报错QA征集第一弹来了哦~包含QA分享一期征集的部分内容,链接附带解决方案,可收藏哦~ npm install安装依赖一直报错?报错https://developer.aliyun.com/ask/301...
问问小秘 2020-06-18 15:46:14 1684 浏览量 回答数 2

问题

【精品问答】前端开发必懂之JS技术二百问

1.document load 和 document ready 的区别 2.JavaScript 中如何检测一个变量是一个 String 类型? 3.请用 js 去除字符串空格? 4.js 是一门怎样的语言&#...
茶什i 2019-12-01 22:05:04 146 浏览量 回答数 0

回答

1 js 的基本数据类型? 2 JavaScript 有几种类型的值? 3 什么是堆?什么是栈?它们之间有什么区别和联系? 4 内部属性 [Class] 是什么? 5 介绍 js 有哪些内置对象? 6 undefined 与 undeclared 的区别? 7 null 和 undefined 的区别? 8 如何获取安全的 undefined 值? 9 说几条写 JavaScript 的基本规范? 10 JavaScript 原型,原型链? 有什么特点? 11 js 获取原型的方法? 12 在 js 中不同进制数字的表示方式? 13 js 中整数的安全范围是多少? 14 typeof NaN 的结果是什么? 15 isNaN 和 Number.isNaN 函数的区别? 16 Array 构造函数只有一个参数值时的表现? 17 其他值到字符串的转换规则? 18 其他值到数字值的转换规则? 19 其他值到布尔类型的值的转换规则? 20 {} 和 [] 的 valueOf 和 toString 的结果是什么? 21 什么是假值对象? 22 ~ 操作符的作用? 23 解析字符串中的数字和将字符串强制类型转换为数字的返回结果都是数字,它们之间的区别是什么? 24 + 操作符什么时候用于字符串的拼接? 25 什么情况下会发生布尔值的隐式强制类型转换? 26 || 和 && 操作符的返回值? 27 Symbol 值的强制类型转换? 28 == 操作符的强制类型转换规则? 29 如何将字符串转化为数字,例如 '12.3b'? 30 如何将浮点数点左边的数每三位添加一个逗号,如 12000000.11 转化为『12,000,000.11』? 31 常用正则表达式? 32 生成随机数的各种方法? 33 如何实现数组的随机排序? 34 javascript 创建对象的几种方式? 35 JavaScript 继承的几种实现方式? 36 寄生式组合继承的实现? 37 Javascript 的作用域链? 38 谈谈 This 对象的理解。 39 eval 是做什么的? 40 什么是 DOM 和 BOM? 41 写一个通用的事件侦听器函数。 42 事件是什么?IE 与火狐的事件机制有什么区别? 如何阻止冒泡? 43 三种事件模型是什么? 44 事件委托是什么? 45 ['1', '2', '3'].map(parseInt) 答案是多少? 46 什么是闭包,为什么要用它? 47 javascript 代码中的 'use strict'; 是什么意思 ? 使用它区别是什么? 48 如何判断一个对象是否属于某个类? 49 instanceof 的作用? 50 new 操作符具体干了什么呢?如何实现? 51 Javascript 中,有一个函数,执行时对象查找时,永远不会去查找原型,这个函数是? 52 对于 JSON 的了解? 53 [].forEach.call($$(''),function(a){a.style.outline='1px solid #'+(~~(Math.random()(1<<24))).toString(16)}) 能解释一下这段代码的意思吗? 54 js 延迟加载的方式有哪些? 55 Ajax 是什么? 如何创建一个 Ajax? 56 谈一谈浏览器的缓存机制? 57 Ajax 解决浏览器缓存问题? 58 同步和异步的区别? 59 什么是浏览器的同源政策? 60 如何解决跨域问题? 61 服务器代理转发时,该如何处理 cookie? 62 简单谈一下 cookie ? 63 模块化开发怎么做? 64 js 的几种模块规范? 65 AMD 和 CMD 规范的区别? 66 ES6 模块与 CommonJS 模块、AMD、CMD 的差异。 67 requireJS 的核心原理是什么?(如何动态加载的?如何避免多次加载的?如何 缓存的?) 68 JS 模块加载器的轮子怎么造,也就是如何实现一个模块加载器? 69 ECMAScript6 怎么写 class,为什么会出现 class 这种东西? 70 documen.write 和 innerHTML 的区别? 71 DOM 操作——怎样添加、移除、移动、复制、创建和查找节点? 72 innerHTML 与 outerHTML 的区别? 73 .call() 和 .apply() 的区别? 74 JavaScript 类数组对象的定义? 75 数组和对象有哪些原生方法,列举一下? 76 数组的 fill 方法? 77 [,,,] 的长度? 78 JavaScript 中的作用域与变量声明提升? 79 如何编写高性能的 Javascript ? 80 简单介绍一下 V8 引擎的垃圾回收机制 81 哪些操作会造成内存泄漏? 82 需求:实现一个页面操作不会整页刷新的网站,并且能在浏览器前进、后退时正确响应。给出你的技术实现方案? 83 如何判断当前脚本运行在浏览器还是 node 环境中?(阿里) 84 把 script 标签放在页面的最底部的 body 封闭之前和封闭之后有什么区别?浏览器会如何解析它们? 85 移动端的点击事件的有延迟,时间是多久,为什么会有? 怎么解决这个延时? 86 什么是“前端路由”?什么时候适合使用“前端路由”?“前端路由”有哪些优点和缺点? 87 如何测试前端代码么? 知道 BDD, TDD, Unit Test 么? 知道怎么测试你的前端工程么(mocha, sinon, jasmin, qUnit..)? 88 检测浏览器版本版本有哪些方式? 89 什么是 Polyfill ? 90 使用 JS 实现获取文件扩展名? 91 介绍一下 js 的节流与防抖? 92 Object.is() 与原来的比较操作符 '==='、'==' 的区别? 93 escape,encodeURI,encodeURIComponent 有什么区别? 94 Unicode 和 UTF-8 之间的关系? 95 js 的事件循环是什么? 96 js 中的深浅拷贝实现? 97 手写 call、apply 及 bind 函数 98 函数柯里化的实现 99 99. 为什么 0.1 + 0.2 != 0.3?如何解决这个问题? 100 原码、反码和补码的介绍 101 toPrecision 和 toFixed 和 Math.round 的区别? 102 什么是 XSS 攻击?如何防范 XSS 攻击? 103 什么是 CSP? 104 什么是 CSRF 攻击?如何防范 CSRF 攻击? 105 什么是 Samesite Cookie 属性? 106 什么是点击劫持?如何防范点击劫持? 107 SQL 注入攻击? 108 什么是 MVVM?比之 MVC 有什么区别?什么又是 MVP ? 109 vue 双向数据绑定原理? 110 Object.defineProperty 介绍? 111 使用 Object.defineProperty() 来进行数据劫持有什么缺点? 112 什么是 Virtual DOM?为什么 Virtual DOM 比原生 DOM 快? 113 如何比较两个 DOM 树的差异? 114 什么是 requestAnimationFrame ? 115 谈谈你对 webpack 的看法 116 offsetWidth/offsetHeight,clientWidth/clientHeight 与 scrollWidth/scrollHeight 的区别? 117 谈一谈你理解的函数式编程? 118 异步编程的实现方式? 119 Js 动画与 CSS 动画区别及相应实现 120 get 请求传参长度的误区 121 URL 和 URI 的区别? 122 get 和 post 请求在缓存方面的区别 123 图片的懒加载和预加载 124 mouseover 和 mouseenter 的区别? 125 js 拖拽功能的实现 126 为什么使用 setTimeout 实现 setInterval?怎么模拟? 127 let 和 const 的注意点? 128 什么是 rest 参数? 129 什么是尾调用,使用尾调用有什么好处? 130 Symbol 类型的注意点? 131 Set 和 WeakSet 结构? 132 Map 和 WeakMap 结构? 133 什么是 Proxy ? 134 Reflect 对象创建目的? 135 require 模块引入的查找方式? 136 什么是 Promise 对象,什么是 Promises/A+ 规范? 137 手写一个 Promise 138 如何检测浏览器所支持的最小字体大小? 139 怎么做 JS 代码 Error 统计? 140 单例模式模式是什么? 141 策略模式是什么? 142 代理模式是什么? 143 中介者模式是什么? 144 适配器模式是什么? 145 观察者模式和发布订阅模式有什么不同? 146 Vue 的生命周期是什么? 147 Vue 的各个生命阶段是什么? 148 Vue 组件间的参数传递方式? 149 computed 和 watch 的差异? 150 vue-router 中的导航钩子函数 151 两个router 的区别? 152 vue 常用的修饰符? 153 computed 和 watch 区别? 154 keep-alive 组件有什么作用? 155 vue 中 mixin 和 mixins 区别? 156 开发中常用的几种 Content-Type ? 157 如何封装一个 javascript 的类型判断函数? 158 如何判断一个对象是否为空对象? 159 使用闭包实现每隔一秒打印 1,2,3,4 160 手写一个 jsonp 161 手写一个观察者模式? 162 EventEmitter 实现 163 一道常被人轻视的前端 JS 面试题 164 如何确定页面的可用性时间,什么是 Performance API? 165 js 中的命名规则 166 js 语句末尾分号是否可以省略? 167 Object.assign() 168 Math.ceil 和 Math.floor 169 js for 循环注意点 170 一个列表,假设有 100000 个数据,这个该怎么办? 171 js 中倒计时的纠偏实现? 172 进程间通信的方式? 173 如何查找一篇英文文章中出现频率最高的单词? 174 174道 JavaScript 面试题,合集
剑曼红尘 2020-04-02 14:05:35 0 浏览量 回答数 0

回答

第一步:安装multer模块 1 cnpm install multer --save 第二步:引入multer模块,构造multer对象: multer(opt) opt是个key-value对象,包含属性dest/storage,fileFilter,limits.分表表示文件的存储位置/方式,文件过滤,文件大小限制.如下: 复制代码 1 var moment = require("moment"); 2 var express = require("express"); 3 var multer = require('multer'); 4 var storage = multer.diskStorage({ 5 //文件存储路径 6 destination: function (req, file, cb) { 7 cb(null, path.join(__dirname, "/../uploads/temps")); 8 }, 9 //修改上传文件的名字 10 //file 是个文件对象 ,fieldname对应在客户端的name属性 11 //存储的文件需要自己加上文件的后缀,multer并不会自动添加 12 //这里直接忽略文件的后缀. 13 filename: function (req, file, cb) { 14 var date = new Date(); 15 cb(null, moment().format("YYYYMMDDhhmmss") + file.originalname); 16 } 17 }); 18 let objMulter = multer({storage : storage }); 复制代码 如果初始化multer时候没有指定dest或者storage,上传的文件将保存在内存中,永远不会写入到磁盘中,在storage中如果没有指定destination值,那么上传的文件将存储在系统默认的临时文件夹. 复制代码 1 multer关联的文件信息: 2 3 filedname : 在form表单中指定的name属性值 4 orginalname : 原始文件名 5 encoding : 文件编码方式 6 mimetype : 多媒体类型 7 size : 文件大小,单位b 8 destination : 文件上传后存储在服务端的路径 9 filename : 文件在服务端的命名 10 path : 文件在服务端的完整路径 11 buffer : 文件二进制数据 12 13 ps:其中destination,filename和path只有在指定storage属性时候有效.而buffer只有文件在内存中存储时候有效. 复制代码 multer同时提供了single/array/fields/any方法用于对接受文件数的控制. single(fieldname) 接收单个文件,通过req.file访问该文件 array(fieldnaem,[maxcount]) 接收多个文件,通过req.files数组方法文件.maxcount指定接收文件最大数. fields(fields) 接受指定fieldname的文件,fieldname由客户端决定,通过req.files数组方法 any 接收所有文件上传,通过req.files访问文件 2.2,fs模块 第一步:安装fs模块,也可直接引用,node默认集成 1 cnpm install fs --save//项目目录安装 2 var fs = require("fs");//直接引入文件系统模块 第二步:介绍fs模块的方法 1 var fs = require('fs'); // 载入fs模块 1,删除指定文件:fs.unlink(path,callback) path参数为该文件的绝对物理路径,callback回调参数当中只有一个错误信息参数err,一般在该文件不存在或者删除文件失败时触发调用。 复制代码 1 fs.unlink('/tmp/234.txt', function(err) { 2 if (err) { 3 throw err; 4 } 5 console.log('成功删除了 /tmp/234.txt'); 6 }); 复制代码 2,读取文件:fs.readFile(filename,[option],callback) 参数说明: filename String 文件名 option Object encoding String |null default=null flag String default='r' callback Function path参数为该文件的绝对物理路径,其中options参数可选,可以传入编码格式,如读取文本文件时,可传入'utf8',若不指定编码格式,则默认输出读取的文件内容为Buffer形式,故一般都会传入该参数。callback回调参数当中有两个参数err和data,其中err为错误信息参数,一般在在文件不存在或者读取文件失败时触发调用,data为文件内容。 复制代码 1 fs.readFile('./tmp/test.txt','utf-8'function(err, data) { 2 // 读取文件失败/错误 3 if (err) { 4 throw err; 5 } 6 // 读取文件成功 7 console.log(data); 8 }); 复制代码 3,写入文件:fs.writeFile(filename,data,[options],callback),追加写入:fs.appendFile(filename,data[,options],callback) filename参数为该文件的绝对物理路径,data为需要写入该文件当中的数据内容,其中options参数可选,可以传入编码格式,若不传则默认为utf8。callback回调参数当中只有一个错误信息参数err,一般在写入失败时触发调用。 复制代码 1 // 写入文件内容(如果文件不存在会创建一个文件) 2 // 传递了追加参数 { 'flag': 'a' } 3 fs.writeFile('./test2.txt', 'test test', { 'flag': 'a' }, function(err) { 4 if (err) { 5 throw err; 6 } 7 8 console.log('Saved.'); 9 10 // 写入成功后读取测试 11 fs.readFile('./test2.txt', 'utf-8', function(err, data) { 12 if (err) { 13 throw err; 14 } 15 console.log(data); 16 }); 17 }); 复制代码 flag传值,r代表读取文件,w代表写文件,a代表追加。 复制代码 1 // 追加写入 2 fs.appendFile("2.txt","我是追加的字符",function (err) { 3 if(err){ 4 return console.log(err); 5 }else { 6 console.log("追加成功"); 7 } 8 }) 复制代码 4,检测文件是否存在:fs.exists(path,callback) path参数传入该文件的绝对物理路径,该callback回调函数有个参数exists。exists为一个文件状态对象,是否存在。 复制代码 1 var dest_Dir = path.join(__dirname.replace("routes", ""), "uploads", destDir); 2 fs.exists(dest_Dir, function (exists) { 3 if (exists) { 4 //存在 5 } 6 else { 7 8 } 9 }); 复制代码 5,移动或重命名指定文件:fs.rename(oldPath,newPath,callback) oldPath参数为该文件原来的路径,newPath参数为该文件移动或重命名之后的路径,这两个参数都必须能传入文件完整的绝对物理路径。callback回调参数当中只有一个错误信息参数,一般在oldPath当中指定的文件不存在或者该操作失败时触发调用。 复制代码 1 fs.rename(sourceFile, destPath, function (err) { 2 res.status(200).json({ 3 httpCode: 200, 4 message: '上传成功', 5 data: { 6 "fileurl": fileurl 7 }, 8 }); 9 }); 复制代码 6,创建一个目录文件夹:fs.mkdir(path[,model],callback) path为该目录的绝对物理路径,callback回调函数当中也只有一个错误信息参数,一般在目录创建失败时触发调用。 复制代码 1 fs.mkdir(dest_Dir, 0777, function (err) { 2 if (err) { 3 res.status(500).json({ 4 5 } else { 6 //创建目录成功,上传文件 7 fs.rename(sourceFile, destPath, function (err) { 8 res.status(200).json({ 9 httpCode: 200, 10 message: '上传成功', 11 data: { 12 "fileurl": fileurl 13 }, 14 }); 15 }); 16 } 17 }) 复制代码 7,读取目录文件夹:fs.readdir(path,callback) path为该目录的绝对物理路径,callback回调函数当中有两个参数err和files,err为错误信息参数,一般在该目录不存在或读取失败时触发调用,files为一个数组对象,包含该目录下的所有文件夹与文件的名字。(仅为文件夹的名字和文件名,不是路径形式)。 复制代码 1 fs.readdir('./newdir', function(err, files) { 2 if (err) { 3 throw err; 4 } 5 // files是一个数组 6 // 每个元素是此目录下的文件或文件夹的名称 7 console.log(files); 8 }); 复制代码 8,删除一个空文件夹:fs.rmdir(path,callback) path为该目录的绝对物理路径,callback回调函数当中也只有一个错误信息参数,一般在该目录不存在或者删除操作失败时触发调用。 复制代码 1 fs.rmdir('/tmp', function(err) { 2 if (err) { 3 throw err; 4 } 5 console.log('成功删除了 空文件夹 tmp'); 6 }); 复制代码 以上的实例均是异步操作,如果需同步操作在函数后面加Sync既可 1 //同步 所有同步的函数都是函数后面加Sync; 2 var res = fs.writeFileSync("1.txt","我是写入内容"); 2.3,文件上传 1,单文件上传 复制代码 1 router.post('/upload', upload.single('file'), function (req, res, next) { 2 var fileName = req.file.filename; 3 var destDir = req.body.dir == undefined ? "default" : req.body.dir; 4 var sourceFile = req.file.path; 5 var destPath = path.join(__dirname.replace("routes", ""), "uploads", destDir, fileName); 6 var dest_Dir = path.join(__dirname.replace("routes", ""), "uploads", destDir); 7 var fileurl = uploadFileDomin + destPath.substr(destPath.indexOf("uploads")); 8 fileurl = fileurl.replace(/\/g, "/"); 9 fs.exists(dest_Dir, function (exists) { 10 if (exists) { 11 fs.rename(sourceFile, destPath, function (err) { 12 res.status(200).json({ 13 httpCode: 200, 14 message: '上传成功', 15 data: { 16 "fileurl": fileurl 17 }, 18 }); 19 }); 20 } 21 else { 22 fs.mkdir(dest_Dir, 0777, function (err) { 23 if (err) { 24 res.status(500).json({ 25 httpCode: 500, 26 message: err, 27 data: [], 28 }); 29 } else { 30 fs.rename(sourceFile, destPath, function (err) { 31 res.status(200).json({ 32 httpCode: 200, 33 message: '上传成功', 34 data: { 35 "fileurl": fileurl 36 }, 37 }); 38 }); 39 } 40 }) 41 } 42 }); 43 44 }); 复制代码 2,多文件上传 复制代码 1 router.post('/uploads', upload.array('file', 8), function (req, res, next) { 2 var paths = []; 3 for (var i = 0; i < req.files.length; i++) { 4 var path = req.files[i].path.replace(/\/g, "/"); 5 var fileurl = uploadFileDomin + path.substr(path.indexOf("uploads")).replace('\', '/'); 6 paths.push(fileurl); 7 } 8 res.status(200).json({ 9 httpCode: 200, 10 message: '上传成功', 11 "fileurls": paths, 12 }); 13 }); 复制代码 最后抛出发送上传接口: 1 app.use("/api", require("./fileUploadApi.js")); 三,前端调用 3.1,单文件上传调用 1,简单html 复制代码 1 ajax upload 2 3 file 4 5 6 复制代码 2,js调用 复制代码 1 $("#btn_upload").click(function () { 2 //创建一个FormDate 3 var formData = new FormData(); 4 //将文件信息追加到其中 5 formData.append('file', file.files[0]); 6 formData.append('dir', 'attachment'); 7 //formData.append('name', file.files[0].name); 8 $.ajax({ 9 url: "http://localhost:3000/api/" + 'upload', 10 type: 'POST', 11 data: formData, 12 cache: false, 13 contentType: false, 14 processData: false, 15 xhrFields: { 16 withCredentials: true 17 }, 18 crossDomain: true, 19 success: function (data) { 20 callBack(data); 21 }, 22 error: function (response) { 23 console.log("error is :" + response); 24 } 25 }); 复制代码 3,实现效果 3.2,多文件上传调用 1,简单html 复制代码 1 ajax multi files upload 2 3 file 4 5 6 7 8 复制代码 2,js调用 复制代码 1 var files1 = $("#files1")[0]; 2 var files2 = $("#files2")[0]; 3 var files3 = $("#files3")[0]; 4 $("#btn_uploads").click(function () { 5 //创建一个FormDate 6 var formData = new FormData(); 7 //将文件信息追加到其中 8 formData.append('file', files1.files[0]); 9 formData.append('file', files2.files[0]); 10 formData.append('file', files3.files[0]); 11 $.ajax({ 12 url: 'http://localhost:3000/api/' + 'uploads', 13 type: 'POST', 14 data: formData, 15 contentType: false, 16 processData: false, 17 async: false, 18 xhrFields: { 19 withCredentials: true 20 }, 21 crossDomain: true, 22 success: function (data) { 23 callBack(data.fileurls); 24 }, 25 error: function (response) { 26 console.log("error is :" + response); 27 } 28 }) 29 }) 复制代码 3,实现效果
游客2q7uranxketok 2021-02-21 00:53:13 0 浏览量 回答数 0

问题

如何优化网站的访问速度

基础知识 很多站长都遇到了网站访问速度不够快的问题,今天来尝试着了解并解决一下这个问题。 先来说一下我们使用浏览器访问一个网页,到看到这个网页出现,中间到底经过了些啥? 首...
cnsjw 2019-12-01 21:00:50 29372 浏览量 回答数 35

问题

充分利用多核优势,高效并行渲染页面--改造nutz使其成为支持并行计算的MVC框架? 400 报错

充分利用多核优势,高效并行渲染页面--改造nutz使其成为支持并行计算的MVC框架? 400 报错 首先我们来看一个场景:          此图为sohu 首页的一部分。 ...
爱吃鱼的程序员 2020-05-29 20:00:06 0 浏览量 回答数 1

问题

充分利用多核优势,高效并行渲染页面--改造nutz使其成为支持并行计算的MVC框架? 400 报错

充分利用多核优势,高效并行渲染页面--改造nutz使其成为支持并行计算的MVC框架? 400 报错 首先我们来看一个场景:          此图为sohu 首页的一部分。 ...
优选2 2020-06-05 16:47:32 0 浏览量 回答数 1

回答

有点明白了,哈哈,异步的话,还是用回调函数吧   getData(function(data){ xxx; }); function getData(callback){ ...; callback(data); ...; } ######ajax可以设置同步!######可以试试用 $.Deferred###### 引用来自“con”的评论 可以试试用 $.Deferred 谢谢,刚才看dom数发现trigger和triggerHandler函数,一查也是看到了deffered,正在试,不过没有试验成功,希望能指导下 使用的jquery1.10.2和easyui1.4 简单地就是一个二级联动菜单,一个事件是一级菜单联动二级菜单,另外一个事件是载入数据的时候将数据写入(不过因为二级菜单跟着一级菜单走,所以得等到二级菜单载入完毕才能写入数据) 下面的代码都是放在$()里面的 //设置一级菜单的二级菜单联动 $('#topic1').combobox({ onChange:function(n,o){ topic2Loaded=false;//因为没有搞懂deferred用法,这个是加的全局变量准备用全局变量来判断 var f_s; //alert(1); f_s=getTopic2(n);    //这个是我现在的简单的存储处理方法 if(f_s==false){ $.post('../server/t_getsubtopic.php',{father:n},function(data,sta,xhr){ jQuery('#topic2').combobox('clear').combobox('loadData',data.topic); eval('db_topic2.'+'f'+n+'=data.topic;'); topic2Loaded=true; },'json'); }else{ jQuery('#topic2').combobox('clear').combobox('loadData',f_s); topic2Loaded=true; } } });        //初始化编辑器的显示内容 jQuery.post('../server/t_editorinit.php',function(data,sta,xhr){ var jjj; jQuery('#topic1').combobox('clear').combobox('loadData',data.topic); jQuery('#saved').attr('value',1); jQuery('#subject').combobox('clear').combobox('loadData',data.subject); if(data.topic.length==0){ jQuery.messager.alert('提示','当前无权限进行操作,请登陆后刷新本页面。','info'); //jQuery('#saved').window('close'); }else{ //是否读取数据,如果是的话读取数据 var id=getURLRequest('id'); if(id){ jQuery.post('../server/getcontent.php',{id:id},function(data,sta,xhr){ var topic=data.path[0]; //jQuery.when(jQuery('#topic1').combobox('select',topic.father.index);); jQuery('#topic1').combobox('select',topic.father.index);                                         //这里就没有看懂,包括看的jquery的api里面then貌似已经废弃了的,这里执行不下去 // jQuery.when(jQuery('#topic1').triggerHandler( // 'onChange',jQuery('#topic1').combobox('getValue') // )).done(jQuery('#topic2').combobox('select',topic.son.topicid)); jQuery('#topic2').combobox('select',topic.son.topicid); //jQuery('#saved').attr('saved')=1; },'json'); } } },'json'); ###### 试了半天没有试出来,现在这样做的,但是看着好丑…… 最主要是如果超500ms没有完成载入就丑了…… jQuery.post('../server/getcontent.php',{id:id},function(data,sta,xhr){ var topic=data.path[0];         jQuery('#topic1').combobox('select',topic.father.index).delay(500).queue(function(){             jQuery('#topic2').combobox('select',topic.son.topicid);         }); jQuery('#saved').attr('saved')=1; },'json'); ###### 1、首先是通过Deferred实现的数据存储 // 存储函数 function getData(dfd, name) { var sdata = []; // 缓存所有ajax请求过的数据 if ( sdata[name] ){ dfd.resolve( sdata[name] ); } else { $.ajax({ url: xxx, }).done( function (data) { sdata[name] = data; dfd.resolve( data ); }) } } // 调用方式 var dfd = $.Deferred(); dfd.done( function (data) { // 拿到数据后要执行的操作 }); getData(dfd, "name1"); Deferred对象的使用方式大抵如上。 2、combobox二级菜单 简单看了下easyui combobox的api,一级菜单被选择时,更新二级菜单内容,可以用类似下面的写法: $("#level_1").combobox({ onSelect: function (record) { // 获取二级菜单内容并缓存,调用上面的getData var dfd = $.Deferred(); dfd.done(function (data) { $("#level_2").combobox( 'loadData', data); }); //这里的record不知道是个啥东西,可能需要加工一下再传入getData getData(dfd, record); } }); 不知道这种方式是不是能满足你说的菜单联动和缓存数据的需求 ###### 引用来自“con”的评论 1、首先是通过Deferred实现的数据存储 // 存储函数 function getData(dfd, name) { var sdata = []; // 缓存所有ajax请求过的数据 if ( sdata[name] ){ dfd.resolve( sdata[name] ); } else { $.ajax({ url: xxx, }).done( function (data) { sdata[name] = data; dfd.resolve( data ); }) } } // 调用方式 var dfd = $.Deferred(); dfd.done( function (data) { // 拿到数据后要执行的操作 }); getData(dfd, "name1"); Deferred对象的使用方式大抵如上。 2、combobox二级菜单 简单看了下easyui combobox的api,一级菜单被选择时,更新二级菜单内容,可以用类似下面的写法: $("#level_1").combobox({ onSelect: function (record) { // 获取二级菜单内容并缓存,调用上面的getData var dfd = $.Deferred(); dfd.done(function (data) { $("#level_2").combobox( 'loadData', data); }); //这里的record不知道是个啥东西,可能需要加工一下再传入getData getData(dfd, record); } }); 不知道这种方式是不是能满足你说的菜单联动和缓存数据的需求 谢谢,因为没用过所以还不太清楚,不过我就当是回调函数理解的话貌似这样的确可以解决问题,有时间的时候我会试着用这个代码并学习一下deferred这个有用的东西的。 至于之前我的解决方式整体就是这样的,不过有eval在里面真的好丑…… var db_topic2={};//用于存储topic2的本地数据,以免频繁进行查询 function getTopic2(father){ //通过查询本地dbTopic2来获取topic2的数据,如果没有的话才进行远程查询 // father='f'+father;//转换为字符 var flag; eval('flag=db_topic2.'+father+';'); if(flag){ return flag; }else{ //通过数据进行查询 return false; } } //设置一级菜单的二级菜单联动 $('#topic1').combobox({ onChange:function(n,o){ $('#saved').prop('value','0');//设置未保存 var f_s; f_s=getTopic2(n); if(f_s==false){ $.post('../server/t_getsubtopic.php',{father:n},function(data,sta,xhr){ jQuery('#topic2').combobox('clear').combobox('loadData',data.topic); eval('db_topic2.'+'f'+n+'=data.topic;'); },'json'); }else{ jQuery('#topic2').combobox('clear').combobox('loadData',f_s); } } }); //载入数据时候的设置 jQuery('#topic1').combobox('select',n.father.index).delay(500).queue(function(){ jQuery('#topic2').combobox('select',n.son.topicid); $(this).dequeue(); }).delay(500).queue(function(){ //因为存在延时,所以得在这里再延时设置已保存状态 $('#saved').prop('value','1');//设置已保存 $(this).dequeue(); }); 看着很丑吧…… ###### /* * 获取数据方法 * name: 数据key * fn: 回调函数 */ function getData(name, fn) { if(typeof getData.cache[name] != "undefined") { fn(getData.cache[name]); return; } $.post("index.php", { name: name }, function (data) { getData.cache[name] = data; fn(data); }, "json"); } getData.cache = {}; //使用实例 getData("user", function (user) { alert(user.name); }); ###### 引用来自“mr-zhuo”的评论 /* * 获取数据方法 * name: 数据key * fn: 回调函数 */ function getData(name, fn) { if(typeof getData.cache[name] != "undefined") { fn(getData.cache[name]); return; } $.post("index.php", { name: name }, function (data) { getData.cache[name] = data; fn(data); }, "json"); } getData.cache = {}; //使用实例 getData("user", function (user) { alert(user.name); }); 谢谢,用回调函数适用范围应该更广一些。###### 这里有篇关于deferred的,不错。 http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html
kun坤 2020-06-07 00:35:34 0 浏览量 回答数 0

回答

前言 这期我想写很久了,但是因为时间的原因一直拖到了现在,我以为一两天就写完了,结果从构思到整理资料,再到写出来用了差不多一周的时间吧。 你们也知道丙丙一直都是创作鬼才来的,所以我肯定不会一本正经的写,我想了好几个切入点,最后决定用一个完整的电商系统作为切入点,带着大家看看,我们需要学些啥,我甚至还收集配套视频和资料,暖男石锤啊,这期是呕心沥血之作,不要白嫖了。 正文 在写这个文章之前,我花了点时间,自己臆想了一个电商系统,基本上算是麻雀虽小五脏俱全,我今天就用它开刀,一步步剖析,我会讲一下我们可能会接触的技术栈可能不全,但是够用,最后给个学习路线。 Tip:请多欣赏一会,每个点看一下,看看什么地方是你接触过的,什么技术栈是你不太熟悉的,我觉得还算是比较全的,有什么建议也可以留言给我。 不知道大家都看了一下没,现在我们就要庖丁解牛了,我从上到下依次分析。 前端 你可能会会好奇,你不是讲后端学习路线嘛,为啥还有前端的部分,我只能告诉你,傻瓜,肤浅。 我们可不能闭门造车,谁告诉你后端就不学点前端了? 前端现在很多也了解后端的技术栈的,你想我们去一个网站,最先接触的,最先看到的是啥? 没错就是前端,在大学你要是找不到专门的前端同学,去做系统肯定也要自己顶一下前端的,那我觉得最基本的技术栈得熟悉和了解吧,丙丙现在也是偶尔会开发一下我们的管理系统主要是VUE和React。 在这里我列举了我目前觉得比较简单和我们后端可以了解的技术栈,都是比较基础的。 作为一名后端了解部分前端知识还是很有必要的,在以后开发的时候,公司有前端那能帮助你前后端联调更顺畅,如果没前端你自己也能顶一下简单的页面。 HTML、CSS、JS、Ajax我觉得是必须掌握的点,看着简单其实深究或者去操作的话还是有很多东西的,其他作为扩展有兴趣可以了解,反正入门简单,只是精通很难很难。 在这一层不光有这些还有Http协议和Servlet,request、response、cookie、session这些也会伴随你整个技术生涯,理解他们对后面的你肯定有不少好处。 Tip:我这里最后删除了JSP相关的技术,我个人觉得没必要学了,很多公司除了老项目之外,新项目都不会使用那些技术了。 前端在我看来比后端难,技术迭代比较快,知识好像也没特定的体系,所以面试大厂的前端很多朋友都说难,不是技术多难,而是知识多且复杂,找不到一个完整的体系,相比之下后端明朗很多,我后面就开始讲后端了。 网关层: 互联网发展到现在,涌现了很多互联网公司,技术更新迭代了很多个版本,从早期的单机时代,到现在超大规模的互联网时代,几亿人参与的春运,几千亿成交规模的双十一,无数互联网前辈的造就了现在互联网的辉煌。 微服务,分布式,负载均衡等我们经常提到的这些名词都是这些技术在场景背后支撑。 单机顶不住,我们就多找点服务器,但是怎么将流量均匀的打到这些服务器上呢? 负载均衡,LVS 我们机器都是IP访问的,那怎么通过我们申请的域名去请求到服务器呢? DNS 大家刷的抖音,B站,快手等等视频服务商,是怎么保证同时为全国的用户提供快速的体验? CDN 我们这么多系统和服务,还有这么多中间件的调度怎么去管理调度等等? zk 这么多的服务器,怎么对外统一访问呢,就可能需要知道反向代理的服务器。 Nginx 这一层做了反向负载、服务路由、服务治理、流量管理、安全隔离、服务容错等等都做了,大家公司的内外网隔离也是这一层做的。 我之前还接触过一些比较有意思的项目,所有对外的接口都是加密的,几十个服务会经过网关解密,找到真的路由再去请求。 这一层的知识点其实也不少,你往后面学会发现分布式事务,分布式锁,还有很多中间件都离不开zk这一层,我们继续往下看。 服务层: 这一层有点东西了,算是整个框架的核心,如果你跟我帅丙一样以后都是从事后端开发的话,我们基本上整个技术生涯,大部分时间都在跟这一层的技术栈打交道了,各种琳琅满目的中间件,计算机基础知识,Linux操作,算法数据结构,架构框架,研发工具等等。 我想在看这个文章的各位,计算机基础肯定都是学过的吧,如果大学的时候没好好学,我觉得还是有必要再看看的。 为什么我们网页能保证安全可靠的传输,你可能会了解到HTTP,TCP协议,什么三次握手,四次挥手。 还有进程、线程、协程,什么内存屏障,指令乱序,分支预测,CPU亲和性等等,在之后的编程生涯,如果你能掌握这些东西,会让你在遇到很多问题的时候瞬间get到点,而不是像个无头苍蝇一样乱撞(然而丙丙还做得不够)。 了解这些计算机知识后,你就需要接触编程语言了,大学的C语言基础会让你学什么语言入门都会快点,我选择了面向对象的JAVA,但是也不知道为啥现在还没对象。 JAVA的基础也一样重要,面向对象(包括类、对象、方法、继承、封装、抽象、 多态、消息解析等),常见API,数据结构,集合框架,设计模式(包括创建型、结构型、行为型),多线程和并发,I/O流,Stream,网络编程你都需要了解。 代码会写了,你就要开始学习一些能帮助你把系统变得更加规范的框架,SSM可以会让你的开发更加便捷,结构层次更加分明。 写代码的时候你会发现你大学用的Eclipse在公司看不到了,你跟大家一样去用了IDEA,第一天这是什么玩意,一周后,真香,但是这玩意收费有点贵,那免费的VSCode真的就是不错的选择了。 代码写的时候你会接触代码的仓库管理工具maven、Gradle,提交代码的时候会去写项目版本管理工具Git。 代码提交之后,发布之后你会发现很多东西需要自己去服务器亲自排查,那Linux的知识点就可以在里面灵活运用了,查看进程,查看文件,各种Vim操作等等。 系统的优化很多地方没优化的空间了,你可能会尝试从算法,或者优化数据结构去优化,你看到了HashMap的源码,想去了解红黑树,然后在算法网上看到了二叉树搜索树和各种常见的算法问题,刷多了,你也能总结出精华所在,什么贪心,分治,动态规划等。 这么多个服务,你发现HTTP请求已经开始有点不满足你的需求了,你想开发更便捷,像访问本地服务一样访问远程服务,所以我们去了解了Dubbo,Spring cloud。 了解Dubbo的过程中,你发现了RPC的精华所在,所以你去接触到了高性能的NIO框架,Netty。 代码写好了,服务也能通信了,但是你发现你的代码链路好长,都耦合在一起了,所以你接触了消息队列,这种异步的处理方式,真香。 他还可以帮你在突发流量的时候用队列做缓冲,但是你发现分布式的情况,事务就不好管理了,你就了解到了分布式事务,什么两段式,三段式,TCC,XA,阿里云的全局事务服务GTS等等。 分布式事务的时候你会想去了解RocketMQ,因为他自带了分布式事务的解决方案,大数据的场景你又看到了Kafka。 我上面提到过zk,像Dubbo、Kafka等中间件都是用它做注册中心的,所以很多技术栈最后都组成了一个知识体系,你先了解了体系中的每一员,你才能把它们联系起来。 服务的交互都从进程内通信变成了远程通信,所以性能必然会受到一些影响。 此外由于很多不确定性的因素,例如网络拥塞、Server 端服务器宕机、挖掘机铲断机房光纤等等,需要许多额外的功能和措施才能保证微服务流畅稳定的工作。 **Spring Cloud **中就有 Hystrix 熔断器、Ribbon客户端负载均衡器、Eureka注册中心等等都是用来解决这些问题的微服务组件。 你感觉学习得差不多了,你发现各大论坛博客出现了一些前沿技术,比如容器化,你可能就会去了解容器化的知识,像**Docker,Kubernetes(K8s)**等。 微服务之所以能够快速发展,很重要的一个原因就是:容器化技术的发展和容器管理系统的成熟。 这一层的东西呢其实远远不止这些的,我不过多赘述,写多了像个劝退师一样,但是大家也不用慌,大部分的技术都是慢慢接触了,工作中慢慢去了解,去深入的。 好啦我们继续沿着图往下看,那再往下是啥呢? 数据层: 数据库可能是整个系统中最值钱的部分了,在我码文字的前一天,刚好发生了微盟程序员删库跑路的操作,删库跑路其实是我们在网上最常用的笑话,没想到还是照进了现实。 这里也提一点点吧,36小时的故障,其实在互联网公司应该是个笑话了吧,权限控制没做好类似rm -rf 、fdisk、drop等等这样的高危命令是可以实时拦截掉的,备份,全量备份,增量备份,延迟备份,异地容灾全部都考虑一下应该也不至于这样,一家上市公司还是有点点不应该。 数据库基本的事务隔离级别,索引,SQL,主被同步,读写分离等都可能是你学的时候要了解到的。 上面我们提到了安全,不要把鸡蛋放一个篮子的道理大家应该都知道,那分库的意义就很明显了,然后你会发现时间久了表的数据大了,就会想到去接触分表,什么TDDL、Sharding-JDBC、DRDS这些插件都会接触到。 你发现流量大的时候,或者热点数据打到数据库还是有点顶不住,压力太大了,那非关系型数据库就进场了,Redis当然是首选,但是MongoDB、memcache也有各自的应用场景。 Redis使用后,真香,真快,但是你会开始担心最开始提到的安全问题,这玩意快是因为在内存中操作,那断点了数据丢了怎么办?你就开始阅读官方文档,了解RDB,AOF这些持久化机制,线上用的时候还会遇到缓存雪崩击穿、穿透等等问题。 单机不满足你就用了,他的集群模式,用了集群可能也担心集群的健康状态,所以就得去了解哨兵,他的主从同步,时间久了Key多了,就得了解内存淘汰机制…… 他的大容量存储有问题,你可能需要去了解Pika…. 其实远远没完,每个的点我都点到为止,但是其实要深究每个点都要学很久,我们接着往下看。 实时/离线/大数据 等你把几种关系型非关系型数据库的知识点,整理清楚后,你会发现数据还是大啊,而且数据的场景越来越多多样化了,那大数据的各种中间件你就得了解了。 你会发现很多场景,不需要实时的数据,比如你查你的支付宝去年的,上个月的账单,这些都是不会变化的数据,没必要实时,那你可能会接触像ODPS这样的中间件去做数据的离线分析。 然后你可能会接触Hadoop系列相关的东西,比如于Hadoop(HDFS)的一个数据仓库工具Hive,是建立在 Hadoop 文件系统之上的分布式面向列的数据库HBase 。 写多的场景,适合做一些简单查询,用他们又有点大材小用,那Cassandra就再合适不过了。 离线的数据分析没办法满足一些实时的常见,类似风控,那Flink你也得略知一二,他的窗口思想还是很有意思。 数据接触完了,计算引擎Spark你是不是也不能放过…… 搜索引擎: 传统关系型数据库和NoSQL非关系型数据都没办法解决一些问题,比如我们在百度,淘宝搜索东西的时候,往往都是几个关键字在一起一起搜索东西的,在数据库除非把几次的结果做交集,不然很难去实现。 那全文检索引擎就诞生了,解决了搜索的问题,你得思考怎么把数据库的东西实时同步到ES中去,那你可能会思考到logstash去定时跑脚本同步,又或者去接触伪装成一台MySQL从服务的Canal,他会去订阅MySQL主服务的binlog,然后自己解析了去操作Es中的数据。 这些都搞定了,那可视化的后台查询又怎么解决呢?Kibana,他他是一个可视化的平台,甚至对Es集群的健康管理都做了可视化,很多公司的日志查询系统都是用它做的。 学习路线 看了这么久你是不是发现,帅丙只是一直在介绍每个层级的技术栈,并没说到具体的一个路线,那是因为我想让大家先有个认知或者说是扫盲吧,我一样用脑图的方式汇总一下吧,如果图片被平台二压了。 资料/学习网站 Tip:本来这一栏有很多我准备的资料的,但是都是外链,或者不合适的分享方式,博客的运营小姐姐提醒了我,所以大家去公众号回复【路线】好了。 絮叨 如果你想去一家不错的公司,但是目前的硬实力又不到,我觉得还是有必要去努力一下的,技术能力的高低能决定你走多远,平台的高低,能决定你的高度。 如果你通过努力成功进入到了心仪的公司,一定不要懈怠放松,职场成长和新技术学习一样,不进则退。 丙丙发现在工作中发现我身边的人真的就是实力越强的越努力,最高级的自律,享受孤独(周末的歪哥)。 总结 我提到的技术栈你想全部了解,我觉得初步了解可能几个月就够了,这里的了解仅限于你知道它,知道他是干嘛的,知道怎么去使用它,并不是说深入了解他的底层原理,了解他的常见问题,熟悉问题的解决方案等等。 你想做到后者,基本上只能靠时间上的日积月累,或者不断的去尝试积累经验,也没什么速成的东西,欲速则不达大家也是知道的。 技术这条路,说实话很枯燥,很辛苦,但是待遇也会高于其他一些基础岗位。 所实话我大学学这个就是为了兴趣,我从小对电子,对计算机都比较热爱,但是现在打磨得,现在就是为了钱吧,是不是很现实?若家境殷实,谁愿颠沛流离。 但是至少丙丙因为做软件,改变了家庭的窘境,自己日子也向小康一步步迈过去。 说做程序员改变了我和我家人的一生可能夸张了,但是我总有一种下班辈子会因为我选择走这条路而改变的错觉。 我是敖丙,一个在互联网苟且偷生的工具人。 创作不易,本期硬核,不想被白嫖,各位的「三连」就是丙丙创作的最大动力,我们下次见! 本文 GitHub https://github.com/JavaFamily 已经收录,有大厂面试完整考点,欢迎Star。 该回答来自:敖丙
剑曼红尘 2020-03-06 11:35:37 0 浏览量 回答数 0

云产品推荐

上海奇点人才服务相关的云产品 小程序定制 上海微企信息技术相关的云产品 国内短信套餐包 ECS云服务器安全配置相关的云产品 开发者问答 阿里云建站 自然场景识别相关的云产品 万网 小程序开发制作 视频内容分析 视频集锦 代理记账服务