前端小白想问,jsp?后面是什么意思,怎么用?求大神解答

前端小白想问,jsp?后面是什么意思,怎么用?求大神解答,第1张

现在前端用Webpack打包JS和其它文件已经是主流了,加上Node的流行,使得前端的工程方式和后端越来越像。所有的东西都模块化,最后统一编译。Webpack因为版本的不断更新以及各种各样纷繁复杂的配置选项,在使用中出现一些迷之错误常常让人无所适从。所以了解一下Webpack究竟是怎么组织编译模块的,生成的代码到底是怎么执行的,还是很有好处的,否则它就永远是个黑箱。当然了我是前端小白,最近也是刚开始研究Webpack的原理,在这里做一点记录。

编译模块

编译两个字听起来就很黑科技,加上生成的代码往往是一大坨不知所云的东西,所以常常会让人却步,但其实里面的核心原理并没有什么难。所谓的Webpack的编译,其实只是Webpack在分析了你的源代码后,对其作出一定的修改,然后把所有源代码统一组织在一个文件里而已。最后生成一个大的bundle JS文件,被浏览器或者其它Javascript引擎执行并返回结果。

在这里用一个简单的案例来说明Webpack打包模块的原理。例如我们有一个模块mAjs

var aa = 1; function getDate() { return new Date(); } moduleexports = { aa: aa, getDate: getDate }

我随便定义了一个变量aa和一个函数getDate,然后export出来,这里是用CommonJS的写法。

然后再定义一个appjs,作为main文件,仍然是CommonJS风格:

var mA = require('/mAjs'); consolelog('mAaa =' + mAaa); mAgetDate();

现在我们有了两个模块,使用Webpack来打包,入口文件是appjs,依赖于模块mAjs,Webpack要做几件事情:

从入口模块appjs开始,分析所有模块的依赖关系,把所有用到的模块都读取进来。 每一个模块的源代码都会被组织在一个立即执行的函数里。 改写模块代码中和require和export相关的语法,以及它们对应的引用变量。 在最后生成的bundle文件里建立一套模块管理系统,能够在runtime动态加载用到的模块。

我们可以看一下上面这个例子,Webpack打包出来的结果。最后的bundle文件总的来说是一个大的立即执行的函数,组织层次比较复杂,大量的命名也比较晦涩,所以我在这里做了一定改写和修饰,把它整理得尽量简单易懂。

首先是把所有用到的模块都罗列出来,以它们的文件名(一般是完整路径)为ID,建立一张表:

var modules = { '/mAjs': generated_mA, '/appjs': generated_app }

关键是上面的generated_xxx是什么?它是一个函数,它把每个模块的源代码包裹在里面,使之成为一个局部的作用域,从而不会暴露内部的变量,实际上就把每个模块都变成一个执行函数。它的定义一般是这样:

function generated_module(module, exports, webpack_require) { // 模块的具体代码。 // }

在这里模块的具体代码是指生成代码,Webpack称之为generated code。例如mA,经过改写得到这样的结果:

function generated_mA(module, exports, webpack_require) { var aa = 1; function getDate() { return new Date(); } moduleexports = { aa: aa, getDate: getDate } }

乍一看似乎和源代码一模一样。的确,mA没有require或者import其它模块,export用的也是传统的CommonJS风格,所以生成代码没有任何改动。不过值得注意的是最后的moduleexports = ,这里的module就是外面传进来的参数module,这实际上是在告诉我们,运行这个函数,模块mA的源代码就会被执行,并且最后需要export的内容就会被保存到外部,到这里就标志着mA加载完成,而那个外部的东西实际上就后面要说的模块管理系统。

接下来看appjs的生成代码:

function generated_app(module, exports, webpack_require) { var mA_imported_module = webpack_require('/mAjs'); consolelog('mAaa =' + mA_imported_module['aa']); mA_imported_module['getDate'](); }

可以看到,appjs的源代码中关于引入的模块mA的部分做了修改,因为无论是require/exports,或是ES6风格的import/export,都无法被JavaScript解释器直接执行,它需要依赖模块管理系统,把这些抽象的关键词具体化。也就是说,webpack_require就是require的具体实现,它能够动态地载入模块mA,并且将结果返回给app。

到这里你脑海里可能已经初步逐渐构建出了一个模块管理系统的想法,我们来看一下webpack_require的实现:

// 加载完毕的所有模块。 var installedModules = {}; function webpack_require(moduleId) { // 如果模块已经加载过了,直接从Cache中读取。 if (installedModules[moduleId]) { return installedModules[moduleId]exports; } // 创建新模块并添加到installedModules。 var module = installedModules[moduleId] = { id: moduleId, exports: {} }; // 加载模块,即运行模块的生成代码, modules[moduleId]call( moduleexports, module, moduleexports, webpack_require); return moduleexports; }

注意倒数第二句里的modules就是我们之前定义过的所有模块的generated code:

var modules = { '/mAjs': generated_mA, '/appjs': generated_app }

webpack_require的逻辑写得很清楚,首先检查模块是否已经加载,如果是则直接从Cache中返回模块的exports结果。如果是全新的模块,那么就建立相应的数据结构module,并且运行这个模块的generated code,这个函数传入的正是我们建立的module对象,以及它的exports域,这实际上就是CommonJS里exports和module的由来。当运行完这个函数,模块就被加载完成了,需要export的结果保存到了module对象中。

所以我们看到所谓的模块管理系统,原理其实非常简单,只要耐心将它们抽丝剥茧理清楚了,根本没有什么深奥的东西,就是由这三个部分组成:

// 所有模块的生成代码 var modules; // 所有已经加载的模块,作为缓存表 var installedModules; // 加载模块的函数 function webpack_require(moduleId);

当然以上一切代码,在整个编译后的bundle文件中,都被包在一个大的立即执行的匿名函数中,最后返回的就是这么一句话:

return webpack_require(‘/appjs');

即加载入口模块appjs,后面所有的依赖都会动态地、递归地在runtime加载。当然Webpack真正生成的代码略有不同,它在结构上大致是这样:

(function(modules) { var installedModules = {}; function webpack_require(moduleId) { // } return webpack_require('/appjs'); }) ({ '/mAjs': generated_mA, '/appjs': generated_app });

可以看到它是直接把modules作为立即执行函数的参数传进去的而不是另外定义的,当然这和上面的写法没什么本质不同,我做这样的改写是为了解释起来更清楚。

ES6的import和export

以上的例子里都是用传统的CommonJS的写法,现在更通用的ES6风格是用import和export关键词,在使用上也略有一些不同。不过对于Webpack或者其它模块管理系统而言,这些新特性应该只被视为语法糖,它们本质上还是和require/exports一样的,例如export:

export aa // 等价于: moduleexports['aa'] = aa export default bb // 等价于: moduleexports['default'] = bb

而对于import:

import {aa} from '/mAjs' // 等价于 var aa = require('/mAjs')['aa']

比较特殊的是这样的:

import m from '/mjs'

情况会稍微复杂一点,它需要载入模块m的default export,而模块m可能并非是由ES6的export来写的,也可能根本没有export default,所以Webpack在为模块生成generated code的时候,会判断它是不是ES6风格的export,例如我们定义模块mBjs:

let x = 3; let printX = () => { consolelog('x = ' + x); } export {printX} export default x

它使用了ES6的export,那么Webpack在mB的generated code就会加上一句话:

function generated_mB(module, exports, webpack_require) { ObjectdefineProperty(moduleexports, '__esModule', {value: true}); // mB的具体代码 // }

也就是说,它给mB的export标注了一个__esModule,说明它是ES6风格的export。这样在其它模块中,当一个依赖模块以类似import m from '/mjs'这样的方式加载时,会首先判断得到的是不是一个ES6 export出来的模块。如果是,则返回它的default,如果不是,则返回整个export对象。例如上面的mA是传统CommonJS的,mB是ES6风格的:

// mA is CommonJS module import mA from '/mAjs' consolelog(mA); // mB is ES6 module import mB from '/mBjs' consolelog(mB);

我们定义get_export_default函数:

function get_export_default(module) { return module && module__esModule module['default'] : module; }

这样generated code运行后在mA和mB上会得到不同的结果:

var mA_imported_module = webpack_require('/mAjs'); // 打印完整的 mA_imported_module consolelog(get_export_default(mA_imported_module)); var mB_imported_module = webpack_require('/mBjs'); // 打印 mB_imported_module['default'] consolelog(get_export_default(mB_imported_module));

这就是在ES6的import上,Webpack需要做一些特殊处理的地方。不过总体而言,ES6的import/export在本质上和CommonJS没有区别,而且Webpack最后生成的generated code也还是基于CommonJS的module/exports这一套机制来实现模块的加载的。

模块管理系统

以上就是Webpack如何打包组织模块,实现runtime模块加载的解读,其实它的原理并不难,核心的思想就是建立模块的管理系统,而这样的做法也是具有普遍性的,如果你读过Nodejs的Module部分的源代码,就会发现其实用的是类似的方法。这里有一篇文章可以参考。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

您可能感兴趣的文章:探索webpack模块及webpack3新特性关于webpack2和模块打包的新手指南(小结)详解react-webpack2-热模块替换[HMR]webpack配置sass模块的加载的方法详解用webpack把我们的业务模块分开打包的方法Webpack常见静态资源处理-模块加载器(Loaders)+ExtractTextPlugin插件详解webpack异步加载业务模块jQuery 移动端拖拽(模块化开发,触摸事件,webpack)

不能单独运行javaweb项目,但可以和tomcat继承来支撑 javaweb项目--说白了就是apache将解析java交给tomcat来解析。

我举一个全站ajax的的建站例子吧。所有页面(包括主页,页眉页脚),静态资源(,JS文件,CSS文件等)都放到apache服务器上,当用户访问apache的静态页面时,页面通过ajax请求将请求发送到tomcat服务器,tomcat处理请求返回数据,通过页面里脚本(jquery或者freemark等)处理请求返回的数据将动态数据填充到静态页面里(或者会发起页面跳转请求等操作)。

最后总结下apache功能强大、高效,但并不能支持JSP及servlet,不太适合作为javaweb的处理服务器,但作为静态资源库和文件服务器,apache比起同类的产品强大的多。建议就像我举例的一样混用apache和tomcat来建站。

1、Apache是一个代理服务器,它可以将您的服务器隐藏在内网,对外暴露的只是Apache服务器,提高您服务器的安全,另外Apache服务服务器解析静态资源(,html页面,css样式文件等)的效率比tomcat要高很多,使用Apache + tomcat将动静资源分开;还有一个很重要的功能,如果您有多台服务器,Apache可以为您提供负载均衡的功能,例您的多台服务器使用同一个对外的出口。

2、您配置了Apache,可以解释html文件,说明您的apache服务器已经正常启动了,出现503的错误,500+的错误表示的是服务器错误,Apache不能解释jsp文件,您需求将jsp,do,action之类的动态文件转发给tomcat去处理,如果您用的是apache 22或以上的版本,您可以使用ProxyPass指令,将访问jsp的页面都交给tomcat去处理,这时候Apache起到的就是代理服务器的作用。

3、8080端口是您的tomcat提供web服务的端口,您可以通过http://{yourServerId}:8080/来访问,8009端口是AJP协议使用的端口,使用这种协议,具有更高的性能,因为它采用的是二进制传输。比HTTP的文本传输要有更高的效率。在Apache中要使用mod_proxy和mod_proxy_ajp,在Tomcat中则要开启ajp服务。ajp服务使用的端口就是8009

希望以上内容对您有帮助。

DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
网站模板库 » 前端小白想问,jsp?后面是什么意思,怎么用?求大神解答

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情