导入零件信息发生错误:未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序_韩某的博客-CSDN博客

mikel阅读(768)

来源: 导入零件信息发生错误:未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序_韩某的博客-CSDN博客

问题描述:

开发导入excel文件时报错“导入零件信息发生错误:未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序”

电脑环境:系统64位,但pc安装的是office2007,32位的

网上查阅相关资料,发现解决方法基本上都是安装“Microsoft Access Driver”数据库引擎,

微软的官方链接“Download Microsoft Access 2010 数据库引擎可再发行程序包”,

点进有两个安装文件

因为电脑是64位的,所以先下载安装的x64的,结果并没有解决问题。

然后又试了试32位的,但仍然不行。

然后参考这个问题的百度知道回答,在IIS管理器中设置启用32位应用程序,单还是不行。

此时已经一脸懵逼了,搞不懂这个问题,然后继续尝试。

 

这个匿名用户的回答虽然图片看不清,但是赞却很多,再看看评论,发现很多网友据此解决了问题,顺着一个评论的思路进行如下设置

 

解决方案右键属性

 

点击属性,平台默认是“Any CPU”

 

点击“配置管理器”,进入配置管理页面,此时“活动解决平台”也是“Any CPU”,下拉此框,选择新建

 

新建x86,点击确定,会发现配置管理器中“活动解决方案平台”变为了x86

 

属性页平台处也变为x86,点击确定

 

然后就可以F5重新调试项目了,发现导入成功,问题解决了。

笔记本装的是windows 7旗舰版64位系统,使用的是MS Office 2007(Microsoft.ACE.OLEDB.12.0,32位程序),开发用的是Visual Studio 2010,我的程序要进行Excel的读写和导出,运行时报“未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序。”网上搜了一下,终于把问题解决了,现总结如下:

步骤一:

先检查安装的MS office程序里是否包含Acess,因为读写Excel需用到Acess数据库引擎。若没有,则下载MS Access 2007数据库引擎并安装,下载地址: http://download.microsoft.com/download/7/0/3/703ffbcb-dc0c-4e19-b0da-1463960fdcdb/AccessDatabaseEngine.exe

步骤二:

如果已安装Acess,出现这个问题的原因是:64位的PC系统上安装了Office的32位版本,而Visual Studio 2010则是64位的,默认生成的是64位程序,这样就造成了程序的不兼容,导致报错。解决方法:在Visual Studio的项目属性里,将生成(build)的目标平台(platform target)由Any CPU改为x86,这样生成(build)出来的就是32位的程序。

SQL Server附加数据库拒绝访问解决方法汇总 - DBing - 博客园

mikel阅读(583)

来源: SQL Server附加数据库拒绝访问解决方法汇总 – DBing – 博客园

方法一:修改权限法

  1. 1

    打开要附加的数据库文件所在的文件夹,即扩展名为mdf的文件所在的文件夹,如下图所示:

  2. 2
    右键单击mdf文件,选择“属性”,如下图所示:
  3. 3

    单击“安全”选项卡,如下图所示:

  4. 4

    单击“编辑”按钮,如下图所示:

  5. 5

    在弹出的对话框中的“组或用户名”中选中”Authenticated Users”,如下图所示:

  6. 6

    在“Authenticated Users的权限”下,勾选”完全控制”,  “完全控制”被勾选后,下面的权限也都会被自动勾选,如下图所示:

  7. 7

    最后点击”确定”就可以了。修改权限完成后,你就可以成功的附加数据库了。这是最常用的方法,成功率也比较高,偶尔出现不成功的案例,此时请参考接下来的两种方法。

    END

方法二:切换身份验证方式法

  1. 1

    有时不能成功附加数据库,可以用切换身份验证方式的方法解决。使用这种解决方法的前提条件是,你之前连接数据库时的身份验证方式是” SQL Server 身份验证 ”,如下图所示。如果你之前是以“Windows身份验证”连接的数据库,不能附加数据库,那么该方法不适合你,请直接参考下面的方法三,如果你忘记了自己是以哪种方式验证的,可以先尝试这种方法,如果不能解决问题,再参考下面的方法三。

  2. 2

    点击“断开连接”按钮,断开当前连接,如下图所示:

  3. 3

    点击“连接”按钮,连接数据库服务器,如下图所示:

  4. 4

    ” 身份验证 “选择“Windows身份验证”,如下图所示:

  5. 5

    连接数据库后,即可附加要附加的数据库了。如果仍然没能成功附加,请参考下面的方法三。

    END

方法三:修改服务法

  1. 打开”SQL Server 配置管理器”程序,如下图所示:

  2. 在左侧单击”SQL Server 服务”, 如下图所示:

  3. 在右侧右键单击“SQL Server (MSLHK)”,选择 “属性”,注意这里的“MSLHK”是我的数据库实例名,在你的电脑上,数据库实例名位置显示的是你的数据库实例名。操作如下图所示:

  4. 在弹出的属性对话框中,在“登录”选项卡下,选中“内置账户”,如下图所示:

  5. 把“内置账户”改为“Local System”,如下图所示:

  6. 点击“确定”按钮,会提示是否重新启动服务,点击“是”。

  7. 重启服务完成后,查看“登录身份为”的显示内容是不是“LocalSystem”,如果是,就说明更改生效,如下图所示:

未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序。 - 天琊蓝 - 博客园

mikel阅读(465)

来源: 未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序。 – 天琊蓝 – 博客园

笔记本装的是windows 7旗舰版64位系统,使用的是MS Office 2007(Microsoft.ACE.OLEDB.12.0,32位程序),开发用的是Visual Studio 2010,我的程序要进行Excel的读写和导出,运行时报“未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序。”网上搜了一下,终于把问题解决了,现总结如下:

步骤一:

先检查安装的MS office程序里是否包含Acess,因为读写Excel需用到Acess数据库引擎。若没有,则下载MS Access 2007数据库引擎并安装,下载地址: http://download.microsoft.com/download/7/0/3/703ffbcb-dc0c-4e19-b0da-1463960fdcdb/AccessDatabaseEngine.exe

步骤二:

如果已安装Acess,出现这个问题的原因是:64位的PC系统上安装了Office的32位版本,而Visual Studio 2010则是64位的,默认生成的是64位程序,这样就造成了程序的不兼容,导致报错。解决方法:在Visual Studio的项目属性里,将生成(build)的目标平台(platform target)由Any CPU改为x86,这样生成(build)出来的就是32位的程序。

 网页渲染性能优化 —— 渲染原理_程序员黑叔的博客-CSDN博客

mikel阅读(464)

来源: (1条消息) 网页渲染性能优化 —— 渲染原理_程序员黑叔的博客-CSDN博客

渲染原理

在讨论性能优化之前,我们有必要了解一些浏览器的渲染原理。不同的浏览器进行渲染有着不同的实现方式,但是大体流程都是差不多的,我们通过 Chrome 浏览器来大致了解一下这个渲染流程。

关键渲染路径

关键渲染路径是指浏览器将 HTML、CSS 和 JavaScript 转换成实际运作的网站必须采取的一系列步骤,通过渲染流程图我们可以大致概括如下:

  1. 处理 HTML 并构建 DOM Tree。
  2. 处理 CSS 并构建 CSSOM Tree。
  3. 将 DOM Tree 和 CSSOM Tree 合并成 Render Object Tree。
  4. 根据 Render Object Tree 计算节点的几何信息并以此进行布局。
  5. 绘制页面需要先构建 Render Layer Tree 以便用正确的顺序展示页面,这棵树的生成与 Render Object Tree 的构建同步进行。然后还要构建 Graphics Layer Tree 来避免不必要的绘制和使用硬件加速渲染,最终才能在屏幕上展示页面。

DOM Tree

DOM(Document Object Model——文档对象模型)是用来呈现以及与任意 HTML 或 XML 交互的 API 文档。DOM 是载入到浏览器中的文档模型,它用节点树的形式来表现文档,每个节点代表文档的构成部分。

需要说明的是 DOM 只是构建了文档标记的属性和关系,并没有说明元素需要呈现的样式,这需要 CSSOM 来处理。

构建流程

获取到 HTML 字节数据后,会通过以下流程构建 DOM Tree:

  1. 编码:HTML 原始字节数据转换为文件指定编码的字符串。
  2. 词法分析(标记化):对输入字符串进行逐字扫描,根据 构词规则 识别单词和符号,分割成一个个我们可以理解的词汇(学名叫 Token )的过程。
  3. 语法分析(解析器):对 Tokens 应用 HTML 的语法规则,进行配对标记、确立节点关系和绑定属性等操作,从而构建 DOM Tree 的过程。

词法分析和语法分析在每次处理 HTML 字符串时都会执行这个过程,比如使用 document.write 方法。

词法分析(标记化)

HTML 结构不算太复杂,大部分情况下识别的标记会有开始标记、内容标记和结束标记,对应一个 HTML 元素。除此之外还有 DOCTYPE、Comment、EndOfFile 等标记。

标记化是通过状态机来实现的,状态机模型在 W3C 中已经定义好了。

想要得到一个标记,必须要经历一些状态,才能完成解析。我们通过一个简单的例子来了解一下流程。

<a href="www.w3c.org">W3C</a>

  • 开始标记:
  • Data state:碰到 <,进入 Tag open state
  • Tag open state:碰到 a,进入 Tag name state 状态
  • Tag name state:碰到 空格,进入 Before attribute name state
  • Before attribute name state:碰到 h,进入 Attribute name state
  • Attribute name state:碰到 =,进入 Before attribute value state
  • Before attribute value state:碰到 ,进入 Attribute value (double-quoted) state
  • Attribute value (double-quoted) state:碰到 w,保持当前状态
  • Attribute value (double-quoted) state:碰到 ,进入 After attribute value (quoted) state
  • After attribute value (quoted) state:碰到 >,进入 Data state,完成解析
  • 内容标记:W3C
  • Data state:碰到 W,保持当前状态,提取内容
  • Data state:碰到 <,进入 Tag open state,完成解析
  • 结束标记:
  • Tag open state:碰到 /,进入 End tag open state
  • End tag open state:碰到 a,进入 Tag name state
  • Tag name state:碰到 >,进入 Data state,完成解析

通过上面这个例子,可以发现属性是开始标记的一部分。

语法分析(解析器)

在创建解析器后,会关联一个 Document 对象作为根节点。

我会简单介绍一下流程,具体的实现过程可以在 Tree construction 查看。

解析器在运行过程中,会对 Tokens 进行迭代;并根据当前 Token 的类型转换到对应的模式,再在当前模式下处理 Token;此时,如果 Token 是一个开始标记,就会创建对应的元素,添加到 DOM Tree 中,并压入还未遇到结束标记的开始标记栈中;此栈的主要目的是实现浏览器的容错机制,纠正嵌套错误,具体的策略在 W3C 中定义。更多标记的处理可以在 状态机算法 中查看。

参考资料

  1. 浏览器的工作原理:新式网络浏览器幕后揭秘 —— 解析器和词法分析器的组合
  2. 浏览器渲染过程与性能优化 —— 构建DOM树与CSSOM树
  3. 在浏览器的背后(一) —— HTML语言的词法解析
  4. 在浏览器的背后(二) —— HTML语言的语法解析
  5. 50 行代码的 HTML 编译器
  6. AST解析基础: 如何写一个简单的html语法分析库
  7. WebKit中的HTML词法分析
  8. HTML文档解析和DOM树的构建
  9. 从Chrome源码看浏览器如何构建DOM树
  10. 构建对象模型 —— 文档对象模型 (DOM)

CSSOM Tree

加载

在构建 DOM Tree 的过程中,如果遇到 link 标记,浏览器就会立即发送请求获取样式文件。当然我们也可以直接使用内联样式或嵌入样式,来减少请求;但是会失去模块化和可维护性,并且像缓存和其他一些优化措施也无效了,利大于弊,性价比实在太低了;除非是为了极致优化首页加载等操作,否则不推荐这样做。

阻塞

CSS 的加载和解析并不会阻塞 DOM Tree 的构建,因为 DOM Tree 和 CSSOM Tree 是两棵相互独立的树结构。但是这个过程会阻塞页面渲染,也就是说在没有处理完 CSS 之前,文档是不会在页面上显示出来的,这个策略的好处在于页面不会重复渲染;如果 DOM Tree 构建完毕直接渲染,这时显示的是一个原始的样式,等待 CSSOM Tree 构建完毕,再重新渲染又会突然变成另外一个模样,除了开销变大之外,用户体验也是相当差劲的。另外 link 标记会阻塞 JavaScript 运行,在这种情况下,DOM Tree 是不会继续构建的,因为 JavaScript 也会阻塞 DOM Tree 的构建,这就会造成很长时间的白屏。

通过一个例子来更加详细的说明:

  1. <!DOCTYPE html>
  2. <html lang=“en”>
  3. <head>
  4. <meta charset=“UTF-8”>
  5. <meta name=“viewport” content=“width=device-width, initial-scale=1.0”>
  6. <meta http-equiv=“X-UA-Compatible” content=“ie=edge”>
  7. <script>
  8. var startDate = new Date();
  9. </script>
  10. <link href=“https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css” rel=“stylesheet”>
  11. <script>
  12. console.log(“link after script”, document.querySelector(“h2”));
  13. console.log(“经过 “ + (new Date() – startDate) + ” ms”);
  14. </script>
  15. <title>性能</title>
  16. </head>
  17. <body>
  18. <h1>标题</h1>
  19. <h2>标题2</h2>
  20. </body>
  21. </html>

首先需要在 Chrome 控制台的 Network 面板设置网络节流,让网络速度变慢,以便更好进行调试。

下图说明 JavaScript 的确需要在 CSS 加载并解析完毕之后才会执行。

为什么需要阻塞 JavaScript 的运行呢?

因为 JavaScript 可以操作 DOM 和 CSSOM,如果 link 标记不阻塞 JavaScript 运行,这时 JavaScript 操作 CSSOM,就会发生冲突。更详细的说明可以在 使用 JavaScript 添加交互 这篇文章中查阅。

解析

CSS 解析的步骤与 HTML 的解析是非常类似的。

词法分析

CSS 会被拆分成如下一些标记:

CSS 的色值使用十六进制优于函数形式的表示?

函数形式是需要再次计算的,在进行词法分析时会将它变成一个函数标记,由此看来使用十六进制的确有所优化。

语法分析

每个 CSS 文件或嵌入样式都会对应一个 CSSStyleSheet 对象(authorStyleSheet),这个对象由一系列的 Rule(规则) 组成;每一条 Rule 都会包含 Selectors(选择器) 和若干 Declearation(声明),Declearation 又由 Property(属性)和 Value(值)组成。另外,浏览器默认样式表(defaultStyleSheet)和用户样式表(UserStyleSheet)也会有对应的 CSSStyleSheet 对象,因为它们都是单独的 CSS 文件。至于内联样式,在构建 DOM Tree 的时候会直接解析成 Declearation 集合。

内联样式和 authorStyleSheet 的区别

所有的 authorStyleSheet 都挂载在 document 节点上,我们可以在浏览器中通过 document.styleSheets 获取到这个集合。内联样式可以直接通过节点的 style 属性查看。

通过一个例子,来了解下内联样式和 authorStyleSheet 的区别:

  1. <!DOCTYPE html>
  2. <html lang=“en”>
  3. <head>
  4. <meta charset=“UTF-8”>
  5. <meta name=“viewport” content=“width=device-width, initial-scale=1.0”>
  6. <meta http-equiv=“X-UA-Compatible” content=“ie=edge”>
  7. <style>
  8. body .div1 {
  9. line-height: 1em;
  10. }
  11. </style>
  12. <link rel=“stylesheet” href=“./style.css”>
  13. <style>
  14. .div1 {
  15. background-color: #f0f;
  16. height: 20px;
  17. }
  18. </style>
  19. <title>Document</title>
  20. </head>
  21. <body>
  22. <div class=“div1” >test</div>
  23. </body>
  24. </html>

可以看到一共有三个 CSSStyleSheet 对象,每个 CSSStyleSheet 对象的 rules 里面会有一个 CSSStyleDeclaration,而内联样式获取到的直接就是 CSSStyleDeclaration。

需要属性合并吗?

在解析 Declearation 时遇到属性合并,会把单条声明转变成对应的多条声明,比如:

  1. .box {
  2. margin: 20px;
  3. }

margin: 20px 就会被转变成四条声明;这说明 CSS 虽然提倡属性合并,但是最终还是会进行拆分的;所以属性合并的作用应该在于减少 CSS 的代码量。

计算

为什么需要计算?

因为一个节点可能会有多个 Selector 命中它,这就需要把所有匹配的 Rule 组合起来,再设置最后的样式。

准备工作

为了便于计算,在生成 CSSStyleSheet 对象后,会把 CSSStyleSheet 对象最右边 Selector 类型相同的 Rules 存放到对应的 Hash Map 中,比如说所有最右边 Selector 类型是 id 的 Rules 就会存放到 ID Rule Map 中;使用最右边 Selector 的原因是为了更快的匹配当前元素的所有 Rule,然后每条 Rule 再检查自己的下一个 Selector 是否匹配当前元素。

  1. idRules
  2. classRules
  3. tagRules
  4. *

选择器命中

一个节点想要获取到所有匹配的 Rule,需要依次判断 Hash Map 中的 Selector 类型(id、class、tagName 等)是否匹配当前节点,如果匹配就会筛选当前 Selector 类型的所有 Rule,找到符合的 Rule 就会放入结果集合中;需要注意的是通配符总会在最后进行筛选。

从右向左匹配规则

上文说过 Hash Map 存放的是最右边 Selector 类型的 Rule,所以在查找符合的 Rule 最开始,检验的是当前 Rule 最右边的 Selector;如果这一步通过,下面就要判断当前的 Selector 是不是最左边的 Selector;如果是,匹配成功,放入结果集合;否则,说明左边还有 Selector,递归检查左边的 Selector 是否匹配,如果不匹配,继续检查下一个 Rule。

为什么需要从右向左匹配呢?

先思考一下正向匹配是什么流程,我们用 div p .yellow 来举例,先查找所有 div 节点,再向下查找后代是否是 p 节点,如果是,再向下查找是否存在包含 class=”yellow” 的节点,如果存在则匹配;但是不存在呢?就浪费一次查询,如果一个页面有上千个 div 节点,而只有一个节点符合 Rule,就会造成大量无效查询,并且如果大多数无效查询都在最后发现,那损失的性能就实在太大了。

这时再思考从右向左匹配的好处,如果一个节点想要找到匹配的 Rule,会先查询最右边 Selector 是当前节点的 Rule,再向左依次检验 Selector;在这种匹配规则下,开始就能避免大多无效的查询,当然性能就更好,速度更快了。

设置样式

设置样式的顺序是先继承父节点,然后使用用户代理的样式,最后使用开发者(authorStyleSheet)的样式。

authorStyleSheet 优先级

放入结果集合的同时会计算这条 Rule 的优先级;来看看 blink 内核对优先级权重的定义:

  1. switch (m_match) {
  2. case Id:
  3. return 0x010000;
  4. case PseudoClass:
  5. return 0x000100;
  6. case Class:
  7. case PseudoElement:
  8. case AttributeExact:
  9. case AttributeSet:
  10. case AttributeList:
  11. case AttributeHyphen:
  12. case AttributeContain:
  13. case AttributeBegin:
  14. case AttributeEnd:
  15. return 0x000100;
  16. case Tag:
  17. return 0x000001;
  18. case Unknown:
  19. return 0;
  20. }
  21. return 0;

因为解析 Rule 的顺序是从右向左进行的,所以计算优先级也会按照这个顺序取得对应 Selector 的权重后相加。来看几个例子:

  1. /*
  2. * 65793 = 65536 + 1 + 256
  3. */
  4. #container p .text {
  5. font-size: 16px;
  6. }
  7. /*
  8. * 2 = 1 + 1
  9. */
  10. div p {
  11. font-size: 14px;
  12. }

当前节点所有匹配的 Rule 都放入结果集合之后,先根据优先级从小到大排序,如果有优先级相同的 Rule,则比较它们的位置。

内联样式优先级

authorStyleSheet 的 Rule 处理完毕,才会设置内联样式;内联样式在构建 DOM Tree 的时候就已经处理完成并存放到节点的 style 属性上了。

内联样式会放到已经排序的结果集合最后,所以如果不设置 !important,内联样式的优先级是最大的。

!important 优先级

在设置 !important 的声明前,会先设置不包含 !important 的所有声明,之后再添加到结果集合的尾部;因为这个集合是按照优先级从小到大排序好的,所以 !important 的优先级就变成最大的了。

书写 CSS 的规则

结果集合最后会生成 ComputedStyle 对象,可以通过 window.getComputedStyle 方法来查看所有声明。

 

可以发现图中的声明是没有顺序的,说明书写规则的最大作用是为了良好的阅读体验,利于团队协作。

调整 Style

这一步会调整相关的声明;例如声明了 position: absolute;,当前节点的 display 就会设置成 block。

参考资料

  1. 从Chrome源码看浏览器如何计算CSS
  2. 探究 CSS 解析原理
  3. Webkit内核探究【2】——Webkit CSS实现
  4. Webkit CSS引擎分析
  5. css加载会造成阻塞吗?
  6. 原来 CSS 与 JS 是这样阻塞 DOM 解析和渲染的
  7. 外链 CSS 延迟 DOM 解析和 DOMContentLoaded
  8. CSS/JS 阻塞 DOM 解析和渲染
  9. 构建对象模型 —— CSS 对象模型 (CSSOM)
  10. 阻塞渲染的 CSS

Render Object Tree

在 DOM Tree 和 CSSOM Tree 构建完毕之后,才会开始生成 Render Object Tree(Document 节点是特例)。

创建 Render Object

在创建 Document 节点的时候,会同时创建一个 Render Object 作为树根。Render Object 是一个描述节点位置、大小等样式的可视化对象。

每个非 display: none | contents 的节点都会创建一个 Render Object,流程大致如下:生成 ComputedStyle(在 CSSOM Tree 计算这一节中有讲),之后比较新旧 ComputedStyle(开始时旧的 ComputedStyle 默认是空);不同则创建一个新的 Render Object,并与当前处理的节点关联,再建立父子兄弟关系,从而形成一棵完整的 Render Object Tree。

布局(重排)

Render Object 在添加到树之后,还需要重新计算位置和大小;ComputedStyle 里面已经包含了这些信息,为什么还需要重新计算呢?因为像 margin: 0 auto; 这样的声明是不能直接使用的,需要转化成实际的大小,才能通过绘图引擎绘制节点;这也是 DOM Tree 和 CSSOM Tree 需要组合成 Render Object Tree 的原因之一。

布局是从 Root Render Object 开始递归的,每一个 Render Object 都有对自身进行布局的方法。为什么需要递归(也就是先计算子节点再回头计算父节点)计算位置和大小呢?因为有些布局信息需要子节点先计算,之后才能通过子节点的布局信息计算出父节点的位置和大小;例如父节点的高度需要子节点撑起。如果子节点的宽度是父节点高度的 50%,要怎么办呢?这就需要在计算子节点之前,先计算自身的布局信息,再传递给子节点,子节点根据这些信息计算好之后就会告诉父节点是否需要重新计算。

数值类型

所有相对的测量值(rem、em、百分比…)都必须转换成屏幕上的绝对像素。如果是 em 或 rem,则需要根据父节点或根节点计算出像素。如果是百分比,则需要乘以父节点宽或高的最大值。如果是 auto,需要用 (父节点的宽或高 – 当前节点的宽或高) / 2 计算出两侧的值。

盒模型

众所周知,文档的每个元素都被表示为一个矩形的盒子(盒模型),通过它可以清晰的描述 Render Object 的布局结构;在 blink 的源码注释中,已经生动的描述了盒模型,与原先耳熟能详的不同,滚动条也包含在了盒模型中,但是滚动条的大小并不是所有的浏览器都能修改的。

  1. // ***** THE BOX MODEL *****
  2. // The CSS box model is based on a series of nested boxes:
  3. // http://www.w3.org/TR/CSS21/box.html
  4. // top
  5. // |—————————————————-|
  6. // | |
  7. // | margin-top |
  8. // | |
  9. // | |—————————————–| |
  10. // | | | |
  11. // | | border-top | |
  12. // | | | |
  13. // | | |————————–|—-| | |
  14. // | | | | | | |
  15. // | | | padding-top |####| | |
  16. // | | | |####| | |
  17. // | | | |—————-| |####| | |
  18. // | | | | | | | | |
  19. // left | ML | BL | PL | content box | PR | SW | BR | MR |
  20. // | | | | | | | | |
  21. // | | | |—————-| | | | |
  22. // | | | | | | |
  23. // | | | padding-bottom | | | |
  24. // | | |————————–|—-| | |
  25. // | | | ####| | | |
  26. // | | | scrollbar height ####| SC | | |
  27. // | | | ####| | | |
  28. // | | |——————————-| | |
  29. // | | | |
  30. // | | border-bottom | |
  31. // | | | |
  32. // | |—————————————–| |
  33. // | |
  34. // | margin-bottom |
  35. // | |
  36. // |—————————————————-|
  37. //
  38. // BL = border-left
  39. // BR = border-right
  40. // ML = margin-left
  41. // MR = margin-right
  42. // PL = padding-left
  43. // PR = padding-right
  44. // SC = scroll corner (contains UI for resizing (see the ‘resize’ property)
  45. // SW = scrollbar width

box-sizing

box-sizing: content-box | border-box,content-box 遵循标准的 W3C 盒子模型,border-box 遵守 IE 盒子模型。

它们的区别在于 content-box 只包含 content area,而 border-box 则一直包含到 border。通过一个例子说明:

  1. // width
  2. // content-box: 40
  3. // border-box: 40 + (2 * 2) + (1 * 2)
  4. div {
  5. width: 40px;
  6. height: 40px;
  7. padding: 2px;
  8. border: 1px solid #ccc;
  9. }

参考资料

  1. 从Chrome源码看浏览器如何layout布局
  2. Chromium网页Render Object Tree创建过程分析
  3. 浏览器的工作原理:新式网络浏览器幕后揭秘 —— 呈现树和 DOM 树的关系
  4. 谈谈我对盒模型的理解
  5. 渲染树构建、布局及绘制

Render Layer Tree

Render Layer 是在 Render Object 创建的同时生成的,具有相同坐标空间的 Render Object 属于同一个 Render Layer。这棵树主要用来实现层叠上下文,以保证用正确的顺序合成页面。

创建 Render Layer

满足层叠上下文条件的 Render Object 一定会为其创建新的 Render Layer,不过一些特殊的 Render Object 也会创建一个新的 Render Layer。

创建 Render Layer 的原因如下:

  • NormalLayer
  • position 属性为 relative、fixed、sticky、absolute
  • 透明的(opacity 小于 1)、滤镜(filter)、遮罩(mask)、混合模式(mix-blend-mode 不为 normal)
  • 剪切路径(clip-path)
  • 2D 或 3D 转换(transform 不为 none)
  • 隐藏背面(backface-visibility: hidden)
  • 倒影(box-reflect)
  • column-count(不为 auto)或者column-widthZ(不为 auto)
  • 对不透明度(opacity)、变换(transform)、滤镜(filter)应用动画
  • OverflowClipLayer
  • 剪切溢出内容(overflow: hidden)

另外以下 DOM 元素对应的 Render Object 也会创建单独的 Render Layer:

  • Document
  • HTML
  • Canvas
  • Video

如果是 NoLayer 类型,那它并不会创建 Render Layer,而是与其第一个拥有 Render Layer 的父节点共用一个。

参考资料

  1. 无线性能优化:Composite —— 从 LayoutObjects 到 PaintLayers
  2. Chromium网页Render Layer Tree创建过程分析
  3. WEBKIT 渲染不可不知的这四棵树

Graphics Layer Tree

软件渲染

软件渲染是浏览器最早采用的渲染方式。在这种方式中,渲染是从后向前(递归)绘制 Render Layer 的;在绘制一个 Render Layer 的过程中,它的 Render Objects 不断向一个共享的 Graphics Context 发送绘制请求来将自己绘制到一张共享的位图中。

硬件渲染

有些特殊的 Render Layer 会绘制到自己的后端存储(当前 Render Layer 会有自己的位图),而不是整个网页共享的位图中,这些 Layer 被称为 Composited Layer(Graphics Layer)。最后,当所有的 Composited Layer 都绘制完成之后,会将它们合成到一张最终的位图中,这一过程被称为 Compositing;这意味着如果网页某个 Render Layer 成为 Composited Layer,那整个网页只能通过合成来渲染。除此之外,Compositing 还包括 transform、scale、opacity 等操作,所以这就是硬件加速性能好的原因,上面的动画操作不需要重绘,只需要重新合成就好。

上文提到软件渲染只会有一个 Graphics Context,并且所有的 Render Layer 都会使用同一个 Graphics Context 绘制。而硬件渲染需要多张位图合成才能得到一张完整的图像,这就需要引入 Graphics Layer Tree。

Graphics Layer Tree 是根据 Render Layer Tree 创建的,但并不是每一个 Render Layer 都会有对应的 Composited Layer;这是因为创建大量的 Composited Layer 会消耗非常多的系统内存,所以 Render Layer 想要成为 Composited Layer,必须要给出创建的理由,这些理由实际上就是在描述 Render Layer 具备的特征。如果一个 Render Layer 不是 Compositing Layer,那就和它的祖先共用一个。

每一个 Graphics Layer 都会有对应的 Graphics Context。Graphics Context 负责输出当前 Render Layer 的位图,位图存储在系统内存中,作为纹理(可以理解为 GPU 中的位图)上传到 GPU 中,最后 GPU 将多张位图合成,然后绘制到屏幕上。因为 Graphics Layer 会有单独的位图,所以在一般情况下更新网页的时候硬件渲染不像软件渲染那样重新绘制相关的 Render Layer;而是重新绘制发生更新的 Graphics Layer。

提升原因

Render Layer 提升为 Composited Layer 的理由大致概括如下,更为详细的说明可以查看 无线性能优化:Composite —— 从 PaintLayers 到 GraphicsLayers。

  • iframe 元素具有 Composited Layer。
  • video 元素及它的控制栏。
  • 使用 WebGL 的 canvas 元素。
  • 硬件加速插件,例如 flash。
  • 3D 或透视变换(perspective transform) CSS 属性。
  • backface-visibility 为 hidden。
  • 对 opacity、transform、fliter、backdropfilter 应用了 animation 或者 transition(需要是 active 的 animation 或者 transition,当 animation 或者 transition 效果未开始或结束后,提升的 Composited Layer 会恢复成普通图层)。
  • will-change 设置为 opacity、transform、top、left、bottom、right(其中 top、left 等需要设置明确的定位属性,如 relative 等)。
  • 有 Composited Layer 后代并本身具有某些属性。
  • 元素有一个 z-index 较低且为 Composited Layer 的兄弟元素。

为什么需要 Composited Layer?

  1. 避免不必要的重绘。例如网页中有两个 Layer a 和 b,如果 a Layer 的元素发生改变,b Layer 没有发生改变;那只需要重新绘制 a Layer,然后再与 b Layer 进行 Compositing,就可以得到整个网页。
  2. 利用硬件加速高效实现某些 UI 特性。例如滚动、3D 变换、透明度或者滤镜效果,可以通过 GPU(硬件渲染)高效实现。

层压缩

由于重叠的原因,可能会产生大量的 Composited Layer,就会浪费很多资源,严重影响性能,这个问题被称为层爆炸。浏览器通过 Layer Squashing(层压缩)处理这个问题,当有多个 Render Layer 与 Composited Layer 重叠,这些 Render Layer 会被压缩到同一个 Composited Layer。来看一个例子:

  1. <!DOCTYPE html>
  2. <html lang=“en”>
  3. <head>
  4. <meta charset=“UTF-8”>
  5. <meta name=“viewport” content=“width=device-width, initial-scale=1.0”>
  6. <meta http-equiv=“X-UA-Compatible” content=“ie=edge”>
  7. <style>
  8. div {
  9. position: absolute;
  10. width: 100px;
  11. height: 100px;
  12. }
  13. .div1 {
  14. z-index: 1;
  15. top: 10px;
  16. left: 10px;
  17. will-change: transform;
  18. background-color: #f00;
  19. }
  20. .div2 {
  21. z-index: 2;
  22. top: 80px;
  23. left: 80px;
  24. background-color: #f0f;
  25. }
  26. .div3 {
  27. z-index: 2;
  28. top: 100px;
  29. left: 100px;
  30. background-color: #ff0;
  31. }
  32. </style>
  33. <title>Document</title>
  34. </head>
  35. <body>
  36. <div class=“div1”></div>
  37. <div class=“div2”></div>
  38. <div class=“div3”></div>
  39. </body>
  40. </html>

 

可以看到后面两个节点重叠而压缩到了同一个 Composited Layer。

有一些不能被压缩的情况,可以在 无线性能优化:Composite —— 层压缩 中查看。

参考资料

  1. 无线性能优化:Composite —— 从-PaintLayers-到-GraphicsLayers
  2. Webkit 渲染基础与硬件加速
  3. Chromium网页Graphics Layer Tree创建过程分析
  4. Chrome中的硬件加速合成
  5. 浏览器渲染流程 详细分析
  6. WebKit 渲染流程基础及分层加速

最后

  1. 感谢阅读,欢迎分享给身边的朋友,
  2. 记得关注噢,黑叔带你飞!

SqlServer 2008R2 10.50.1600.1 升级到 SqlServer 2016_lwbjyl 笔记-CSDN博客

mikel阅读(550)

来源: (1条消息) SqlServer 2008R2 10.50.1600.1 升级到 SqlServer 2016_lwbjyl 笔记-CSDN博客

要从SQL server 2008 R2 企业版 直接升级到 2016 企业版, 要先把R2升级到SP3这个版本(注意:不是sp1,sp2,sp3的安全更新【坑】)。然后去下载2016(去itellyou下载),选择从历史版本升级(是直接把默认实例及数据库引擎升上去,不是升级的 SSMS-SQL Server Management Studo管理工具)

以下都是装的x64 版本(如果SQL SERVER 版本为X86应该装x86相应的,补丁编号一致,如:SQLServer2008R2SP1-KB2528583-x86-CHS.exe)

一、10.50.1600.1->10.50.2500.0 ->Microsoft® SQL Server® 2008 R2 的 Service Pack 1

 

下载列表:https://www.microsoft.com/zh-cn/download/confirmation.aspx?id=26727

64位版本:

https://download.microsoft.com/download/0/9/9/099E0C83-072B-42A5-83A0-9BB3D2E6E2A3/SQLServer2008R2SP1-KB2528583-x64-CHS.exe

二、10.50.2500.0->10.50.4000.0 ->Microsoft® SQL Server® 2008 R2 的 Service Pack 2

下载列表:“https://www.microsoft.com/zh-cn/download/confirmation.aspx?id=30437

64位版本:

https://download.microsoft.com/download/C/A/F/CAFB17CE-64EE-4543-B3E1-241460313A73/SQLServer2008R2SP2-KB2630458-x64-CHS.exe

三、10.50.4000.0->10.50.6000.34 Microsoft® SQL Server® 2008 R2 的 Service Pack 3

下载列表:https://www.microsoft.com/zh-CN/download/details.aspx?id=44271

64位下载

https://download.microsoft.com/download/9/6/4/964BB4EC-FC28-4DA7-9295-7D4A8FDBE1A4/CHS/SQLServer2008R2SP3-KB2979597-x64-CHS.exe

 

 

装完以上三个sp 补丁包后

用sql server 2016 完整安装包安装

下载地址:

ed2k://|file|cn_sql_server_2016_developer_x64_dvd_8776722.iso|2452795392|EF6BAADFBCC9C647180B0F93FD0186D0|/

开始安装升级

 

后面就下一步下一步之类的。如果遇到错误,就重试下

 

 

 

 

Over。。。记个笔记。
————————————————
版权声明:本文为CSDN博主「Jalan.Wang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lwbjyl/article/details/88029243

推荐一款非常强大的扒站工具 - 最骚的就是你 - 博客园

mikel阅读(819)

来源: 推荐一款非常强大的扒站工具 – 最骚的就是你 – 博客园

在平时的开发或者学习的过程中,我们难免会看到一些让人心动的网站,于是自己想把它弄下来,自己手工一个文件一个文件把它保存下来不太可能,那得累死你,下面我推荐一款扒站的神器,可以把你所喜欢的目标网站整个网站给扒下来,这个神器就是teleport ultra。下面简单介绍下使用教程。

下载与安装

首先到官网下载:http://www.tenmax.com/teleport/ultra/download.htm ,然后按照软件的安装指引完成安装

扒站步骤

1、打开软件

2、点击File,然后点击 New Project Wizred…,弹出如下界面,选择第一项,点击下一步

3、然后在输入框输入你要扒的网站的地址,点击下一步

4、选择everything,点击下一步,然后点击完成

5、选择本地保存网站源文件的路径后,点击保存

6、再单击start,即开始扒网站的文件

7、完成扒站

移动支持 – ASP.NET MVC 4 系列 - SkySoot - 博客园

mikel阅读(1002)

来源: 移动支持 – ASP.NET MVC 4 系列 – SkySoot – 博客园

       目前,有各种各样的方法可以提高网站应用程序的移动体验。在某些情况下,我们只想在小规格上做一些微小的风格变化;另一些情况下,我们可能完全改变外观显示或者一些视图的内容;最极端的情况下,我们可能重新创建一个专门针对移动用户的 Web 应用程序。针对这些情况,MVC 4 提供了如下几种方案:

  • 适应性呈现:默认的 Internet 和 Intranet 应用程序模板使用 CSS 媒体查询(CSS media queries)来缩小到较小的移动规格(mobile form factors)。
  • 显示模式:MVC 4 采用了基于约定的方法,可以根据发出请求的浏览器选择不同的视图。与适应性不同,显示模式允许我们改变发往移动浏览器的标记!
  • Mobile Project 模板:这个新的项目模板帮助创建只针对移动设备使用的 Web 应用程序。

 

适应性呈现

       image   image

       MVC 4 默认模板在移动浏览器中做了很多处理,显而易见,页面智能的根据移动设备屏幕尺寸进行缩放,而不是简单的缩小页面尺寸(收缩文本和其他元素),为了能在移动设备上使用,页面进行了重绘。页面利用的是两个普遍支持的浏览器功能:

       Viewport 元标记

           基于浏览器嗅探或用户选择,Viewport 标记只在那些专门为小规格设计的页面中使用。这种情况下,我们按如下方式使用 Viewport 标记:

       <meta name=”viewport” content=”width=320″ />  // 不适用于大尺寸页面

           一个更好的解决方案是把我们的 CSS 扩展到各种规模,然后告诉浏览器支持任意设备!这很容易实现:

       <meta name=”viewport” content=”width=device-width” />

       CSS 媒体查询的自适应样式

           我们已经告诉浏览器页面足够智能,可以自动缩放到当前设备的屏幕尺寸。但如何兑现这一承诺呢?答案是 CSS 媒体查询。CSS 媒体查询允许我们在特定的媒体(显示)功能指定 CSS 规则,CSS 规则进行自上而下的评估,我们可以在 CSS 文件的顶部应用一般的规则,用专门在 CSS 中进行小规格显示的规则进行重写,并且媒体查询环绕这些规则,以使它们不能在大规格显示的浏览器中使用

 

       列举一个非常简单的示例,当宽度大于 850px 的屏幕上显示时,背景是蓝色,否则红色。CSS 如下:

body {
    background-color: blue;
}
 
@media only screen and (max-width:850px) {
    body {
        background-color: red;
    }
}

image

image

 

显示模式

       MVC 4 中的视图逻辑已经改变,添加了基于约定的替代视图。当浏览器用户代理显示是一个已知的移动设备时,默认的视图引擎首先查找名称以 .Mobile.cshtml 结尾的视图。例如,桌面浏览器请求主页时,应用程序使用 Views\Home\Index.cshtml 模板,而当移动浏览器请求主页时,程序就会使用 Views\Home\Index.Mobile.cshtml 模板。这些都由约定来处理,我们不必配置或注册

       (这里不方便测试就不贴图了,有兴趣的朋友可以下载移动浏览器模拟器来启动项目自行测试)

 

Mobile Project 模板

       如果需要创建只针对移动浏览器使用的应用程序,可以使用 Mobile Site 模板来创建新应用程序。该模版为我们创建的网站预先配置使用 JQuery Mobile 库,这个库为移动 Web 应用程序提供了大量增强功能:

  • 用户界面采用触摸优化的 UI 小部件
  • 为主要的移动浏览器而设计,并通过了测试
  • Ajax 导航提供了动画页面过渡,使其在低带宽的情况下,依然保持良好的性能
  • 通过主题支持,我们可以使用 CSS 主题重置整个网站的皮肤
  • 列表视图使用移动友好的接口,为浏览和操纵信息列表提供了很好的用户体验

image image image

       Mobile Project 模板可以开发强大的 JQuery Mobile ASP.NET MVC 应用程序,但这需要深入了解 jQuery Mobile。可以参考一些学习资料:

ASP.NET MVC Display Mode 移动端视图 配置对微信内置浏览器的识别 - Cameron - 博客园

mikel阅读(791)

来源: ASP.NET MVC Display Mode 移动端视图 配置对微信内置浏览器的识别 – Cameron – 博客园

最近在捣鼓一个稍微有点low的商城网站,没有计划做app却要求有个wap版,而前端又没有做成响应式,时间WTF,直接利用了ASP.NET mvc的Display Mode Provider

使用方式依照上面的链接地址,ASP.NET mvc application启动的时候会在全局变量 DisplayModeProvider.Instance.Modes 集合中加入 DisplayModeId == “Mobile” 的 IDisplayMode ,因此如果想要在移动端浏览器中展示移动视图只需要添加对应的以 .Mobile.cshtml 结尾的视图文件就可以了;可以通过chrome浏览器F12模拟移动端进行测试。

通过查看mvc源码发现IDisplayMode的默认实现为 DefaultDisplayMode ,它通过 HttpContext.GetOverriddenBrowser().IsMobileDevice 来判断是否为移动端,如果Controller需要针对pc端及mobile端做不同处理可以通过这种方式来判断,其他方式可能会造成两边不一致。

从GetOverriddenBrowser这个命名可以看出它的判断结果是可以通过某种方式改变的,也就是视图切换,实现如下:

复制代码
public RedirectResult SwitchView(bool mobile, string returnUrl)
{
    if (Request.Browser.IsMobileDevice == mobile)
        HttpContext.ClearOverriddenBrowser();
    else
        HttpContext.SetOverriddenBrowser(mobile ? BrowserOverride.Mobile : BrowserOverride.Desktop);

    return Redirect(returnUrl);
}
复制代码

在做的过程中我就在考虑,web server判断web client无非是通过传过去userAgent字符串,.net framework原生不可能准确判断每一种移动端设备,顶多预存了一些比较普遍的浏览器的userAgent;果不其然,在微信内置浏览器中打开呈现的是pc版的视图。再次定位到HttpContext.GetOverriddenBrowser().IsMobileDevice,其值在未被重写的时候是直接通过 Request.Browser.IsMobileDevice 得到的,它的结果由来是通过 C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\Browsers 中的配置文件来决定的:

里面的配置是xml格式,通过命名可以大致猜出含义,我唯一不明白的是里面browser节点和gateway节点的区别;很奇怪,这一块的知识国内搜索引擎基本搜不到,fan墙google勉强找到一篇介绍这个的https://www.codeproject.com/Articles/1088703/How-to-detect-browsers-in-ASP-NET-with-browser-fil,写的比较详细,按照该作者对Edge浏览器的配置,写了一个wechat.browser:

复制代码
<browsers>
  <!-- mozilla/5.0 (linux; u; android 4.1.2; zh-cn; mi-one plus build/jzo54k) applewebkit/534.30 (khtml, like gecko) version/4.0 mobile safari/534.30 micromessenger/5.0.1.352  -->
  <browser id="WechatInAndroid" parentID="Chrome">
    <identification>
      <userAgent match="MicroMessenger" />
      <userAgent match="Safari" />
    </identification>

    <capabilities>
      <capability name="isMobileDevice"           value="true" />
      <capability name="mobileDeviceManufacturer" value="Google" />
      <capability name="mobileDeviceModel"        value="Android" />
      <capability name="canInitiateVoiceCall"     value="true" />
    </capabilities>
  </browser>
</browsers>
复制代码

wechat内置浏览器的userAgent比较另类,Android中都还有safari;其中MicroMessenger是它特有的,判断有这个就将isMobileDevice设置为true就行了。上面写的有点偷懒,都没有使用正则判断出版本号,也没有过滤桌面版微信~

在web项目中新建App_Browsers文件夹然后将wechat.browser即可生效。

The End.

原文地址:http://www.cnblogs.com/CameronWu/p/6764045.html

实时开发框架Meteor API解读系列 Meteor.methods_Keep Moving-CSDN博客

mikel阅读(684)

来源: 实时开发框架Meteor API解读系列 Meteor.methods_Keep Moving-CSDN博客

写在前面的话
该系列是零散的。 写到哪个是哪个 不会有个顺序。
尽量一篇博客一个API
尽量搭配一个代码实例 (因为时间比较零碎不一定能够保证)
每篇博文我会标记所使用的Meteor版本,防止因为API变化,导致博客的内容的正确性问题
能够看懂官方API就尽量看官方的,官方的才是最准确的。我这里只是提供一个参考
V 0.7.01

本篇文章涉及到的API:Meteor.methods,Meteor.call,Meteor.apply,Meteor.starup
Meteor.methods — Anywhere
关于 Meteor.methods 先看一下官方的简单描述

Defines functions that can be invoked over the network by clients.

大概意思就是 定义一些方法可以被客户端通过网络进行调用。注意下面的解释都是以这一条为基础来解释的。

ps:因为我初次看官方文档就糊涂了。不知道大家注意了没有,官方文档在每个API 后面有个标记,标记api的使用范围是在客户端(Client)使用还是服务端(Server)使用,亦或是同时都可以使用(Anywhere)。
在Meteor.methods后面的标识是Anywhere我的第一反应是服务端通过Meteor.methods定义的方法客户端可以调用,客户端通过Meteor.methods定义的方法服务端可以调用。其实如果稍微思考一下就会知道这样想是错误的。因为客户端有那么多,Meteor怎么知道到底使哪个客户端来执行这个方法呢? 但是这里的Anywhere是什么意思呢?稍后解释。

*强调 该API的作用也可以说它的主要目的是实现: 在服务端定义一组方法,使客户端能够调用。换句话说,通过这个API,客户端可以命令服务端做一些我们允许做的事情。
client 端定义的Meteor.methods叫做 ‘stub’(官方用的是这个单词) ,至于怎么翻译,看个人理解吧。这是下文需要用的一个描述。[我翻译成’存根’,理解为 对服务端方法调用的客户端补充动作。]
参数:Object
函数Meteor.methods的参数是一个object对象,这个对象里面的属性名就是供客户端调用的函数名,该属性对应的值就是共调用的函数。
例如:

{
“hello”:function(){..},
“welcome”:function(){..},
“bey”:function(){..}
}
如下使用:(服务端)

Meteor.methods({
“say”:function(name){
//do somthing
console.log(“Hello ” + name);
return “Hello boy”;
} ,
“draw”:function(…){
…..
},
…..
});
返回值:JSON对象(官方原文是: EJSON-able value)或者一个Meteor.Error对象

Meteor.Error 当后台处理到异常时,应该主动抛出的出错信息。这是一个Meteor自定义的一个异常对象。这个对象与本篇主题不相关,暂不做解释。可能一篇博客介绍它。
在被调用函数的内部 (如say对应函数的内部)存在一个上下对象 this。这个对象组成如下:

{
isSimulation: Boolean,// a boolean value, true if this invocation is a stub.
unblock: Function,//when called, allows the next method from this client to begin running.
userId: String,//the id of the current user.
setUserId: Function//a function that associates the current client with a user.
connection: Object//on the server, the connection this method call was received on.
}
根据官方的解释可能不是很i清楚,后面我们通过代码进行测试。

现在Meteor.methods的参数类型,和其中的函数应用已经讲,那么接着讲 如何来调用这些在Server端定义的内容。

有两个方法可以使用

1. Meteor.call
2. Meteor.apply
(个人认为:这两个方法的区别有点类似js的call与apply的区别)

Meteor.call — Anywhere
具体形式如下:

Meteor.call(“function name”,arg1,arg2,..,function(error,result){
//do something
});
function nanme 表示 在Meteor.methods中定义的对象的属性名,通过这个属性名来表示调用服务端对应的这个方法。

arg1,arg2,.. 是任意个参数,这个参数将作为服务端函数的参数。

注意这些参数仅为json或者一般数据类型,不能传递包含function对象
最后一个是回调函数。如果服务端函数抛出异常则 将赋值给error这个参数。
如果没有异常抛出,则服务端函数的返回值将赋值给result这个参数。

接下来看具体实现和代码。

meteor create api-001 #创建meteor应用
cd api-001 #进入应用目录
rm *.html *.css *.js #删除自动生成的.html,css,js文件
mkdir server #创建server文件夹
mkdir client #创建client文件夹
(关于文件夹的作用请参考其他人博客,或官方文档,我暂时还没有写。)
在server文件夹中新建一个js文件,如 main.js 内容如下:

Meteor.methods({
“test”:function(){
console.log(“Hello I’m Server”);
}
});
现在代码已经完成了,运行这个工程。
用浏览器(建议使用Chrome,该系列博客都将以此浏览器进行)打开http://localhost:3000 按F12 进入开发者模式 找到console控制台,输入:

Meteor.call(“test”)
这时在meteor启动的命令窗口将看到字符串输出。这就是Meteor.call的使用了。客户端调用服务端的方法。

(这里使用chrome控制台来完成相关测试是为了尽量保持博客的简洁性。同样的语句当然也可以写到客户端的js文件中,然后在html中引用,调用。效果是一样的,但是对于这篇博客来说 代码量就显的繁琐了。关于chrome的开发者模式的使用,请查找资料,或者查看我的博客如果你在看这篇博客时我已经写了的话)
最简单的demo已经了解过了,接下来看下它的返回值和参数的传递。
改动一下 main.js:

Meteor.methods({
//这里的参数可以是N个
“test”:function(a,b){
console.log(a + ” ” + b);
//这里使用的返回类型是json对象,当然可以使用基本数据类型,如string,number,bool等
return {
a:a,
b:b,
c:a+b
}
}
});
meteor自动重启。同样在chrome控制台输入:

Meteor.call(“test”,1,2,function(error,result){
//服务端抛出的异常将被这个回调函数的地一个参数接收,也就是error
//当服务端无异常抛出时,error为undefined
if(error){
console.log(“服务端异常”);
console.log(error);
return;
}
//服务端函数的返回值将被第二个参数接受,也就是result
console.log(result);
});
打印结果很明确就是服务端的返回值。

注意,因为Meteor.call可以在Server和Client同时使用,
在Server端运行Meteor.call时,最后一个参数不是回调函数的话,在可能的情况下服务端将同步执行这个方法体)验证代码如下 main.js:

var fs = Npm.require(‘fs’);
Meteor.methods({
“test”:function(a){
return a;
}
});

Meteor.startup(function(){
var s = Meteor.call(“test”,5);
console.log(s);
});

强调!这仅是在Server可以这样用,在Client如果要取到Server的返回值,必须使用回调函数才能获取到。
————————————
现在,下面的这个结论如果不能理解或者对你造成了迷惑请忽略它,因为它的实际作用不大。只是因为API中对它有个简单的提及,那么就用代码代码验证一下。
文档原文:
“On the client, if you do not pass a callback and you are not inside a stub, call will return undefined, and you will have no way to get the return value of the method.”
原文就是上面这样了。不知道你思考了没有我上面提及到的这句话伸展:”在Client如果要取到Server的返回值”。 什么伸展呢?因为Meteor.methods在客户端也可以使用,那么如果Client 的Meteor.call调用Client的Meteor.methods中的函数 是不是也需要用回调函数呢? 结论是:不一定需要。
但是根据原文文档(原文没有直接提及,是根据”you do not pass a callback and you are not inside a stub”推断出来的,所以说这个结论实际作用不大),你得满足一个条件才行。条件是:你的Meteor.call必须在stub[前文已经解释过]中。(当然Client 的Metoer.methods本身不能涉及到异步调用。这个和Server端的同步是同样的样要求),而且在sub中使用Method.call 只会调用Client 的Meteor.methods中定义的方法,而Server的Meteor.methods不会执行。
官方文档提到了这个上面的这个情况。原文如下:
“Finally, if you are inside a stub on the client and call another method, the other method is not executed (no RPC is generated, nothing ‘real’ happens). If that other method has a stub, that stub stands in for the method and is executed.”

通过以下代码的运行就能看到:
Server/main.js

Meteor.methods({
hello:function(){
console.log(“server”);
return 10;
}
});

Client/client.js

Meteor.methods({
hello:function(){
console.log(“clent”);
return 12;
},
say:function(){
console.log(‘say’);
var hello = Meteor.call(“hello”);//Server下的hello 不会执行。
console.log(hello);//打印值是12
}
});

Meteor.apply — Anywhere
服务端代码不需要改动,在浏览器控制台输入:

Meteor.apply(“test”,[1,2],function(errror,result){
if(error){
//do something;
return;
}
// do somthing
console.log(result);
});
可以看到 Meteor.apply和Meteor.call 在一般用法 上基本没区别,仅是传递参数的方式不同而已,一个使用参数列表,一个使用参数数组。其实对于大多数 开发过程而言 掌握上述两种的使用已经能够满足开发需要了。因此对无更多要求的人而言,本篇博客可以到此为止。前文提到的 服务端函数 内部的上下文对象的使用 和 关于Meteor.methods的Anywhere 这两个还没解释的地方 可以忽略了。

Meteor.methods的Anywhere
大家细心一点可能发现Meteor.call,Meteor.apply同样是”Anywhere”.

先解释一下Server的call,apply和Client的call,apply的区别。

区别很简单:

Server:
仅能调用服务端的Meteor.methods中定义的函数
Client:
同时调用服务端和客户端的Meteor.methods中定义的函数。这个涉及到了Meteor.methods的Anywhere了。具体请往下看。
因为前面已经介绍了methods,call,apply的简单用法了。那么下面的代码就尽量简化不再描述这些了。

首先修改server的main.js。内容如下:

Meteor.methods({
“test”:function(a){
console.log(“server”);
return a+1;
}
});
//Meteor加载完所有文件后将执行这个方法。具体使用请参考官方文档,比较简单。
Meteor.startup(function(){
//然meteor启动后执行test方法
Meteor.call(“test”,1,function(err,result){
console.log(result);
});
});
另外,最开始的时候就新建了一个client文件,在该文件夹下 新建一个js文件,如client.js
内容如下:

Meteor.methods({
“test”:function(a){
console.log(“Client”);
return a+”aaa”;
}
});
代码基本就这样 然后重新运行meteor.

可以看到在Meteor.startup调用的Meteor.call只执行了Server下定义的test函数。

接着打开Chrome的控制台,输入:

Meteor.call(“test”,1,function(err,result){
console.log(result);
});
可以发现,客户端Meteor.methods和服务端Meteor.methods定义的test方法都执行了。而且在这个call函数的里回调函数的返回值 是服务端test的返回值,客户端test函数的返回值自动被舍弃了。

如果Client和Server同时定义了Meteor.methods 函数,在进行调用时,server 执行Meteor.call或Meteor.apply 只会使Server端的Meteor.methods中定义的函数执行
,而Client端执行的call和apply 会同调用客户端和服务端中Meteor.methods定义的函数。
且返回值都是以Server端的函数返回值,客户端的返回值将自动舍弃。其实这个结论自己多写几个代码就能够了解。
到这里 Meteor.methods的Anywhere不用再解释,应该也明白了。

Meteor.methods中函数的上下文对象 this
this中包含五个属性如下 (这些当需要用到时,能够想起有怎么个属性存在就可以了。到时候会自动知道该怎么使用)

{
isSimulation: Boolean,// a boolean value, true if this invocation is a stub.
unblock: Function,//when called, allows the next method from this client to begin running.
userId: String,//the id of the current user.
setUserId: Function//a function that associates the current client with a user.
connection: Object//on the server, the connection this method call was received on.
}
this.userId
调用这个函数的用户的id ,类型:string。如果用户没有登录,值为null。 该属性在 Server的Meteor.methods和Client的Meteor.methods都存在。用官方的描述就是Anywhere。 这个属性依赖Meteor的accounts 模块。这里不赘述。

this.setUseId 类型:Function,该setUerId函数的接收一个字符串或者null。使用范围:Server 设置当前链接的 用户。也就是说可以改变登录用户,或者使用户登录[如果this.userId为null],注销登录用户[this.setUserId(null)] .同样需要 Meteor的accounts模块的支持。

this.isSimulation 类型:Boolean 。使用范围:Anywhere
这个属性 我解释不好(如有好的理解请在博客下方留言),官方的解释是这样的:

Access inside a method invocation. Boolean value, true if this invocation is a stub.
[我理解意思是在Client的Meteor.methods中该值为true,Server中为false]。而且经过代码如下代码测试貌似和我理解的意思差不多 :

1. Server的call 或apply调用时,在Server的Meteor.methods中“`isSimulation“`为false

2. Client的call或apply调用时,
在Server的Meteor.methods中“`isSimulation“`为false,
在Client的Meteor.methods中“`isSimulation“`为true
测试代码:
client.js:

Meteor.methods({
“test”:function(a){
console.log(“Client”);
console.log(this.isSimulation); //false
return a+”aaa”;
}
});
main.js:

Meteor.methods({
“test”:function(a){
console.log(“server”);
console.log(this.isSimulation);//true
return a+1;
}
});

Meteor.startup(function(){
Meteor.call(“test”,1,function(err,result){
console.log(result);
});
});
4 this.unblock()
解释这个之前,我刚才得到了一个结论,一直没有注意到(没有使用过this.unblick()也没注意过它是否是阻塞的,写博客确实也是一种自我学习过程,当然这是题外话了。)的结论。默认情况下在Client调用Server端的函数这种过程是阻塞式的。意识就是说,如果有多个客户端同时调用test这个函数,而test这个函数的执行需要耗费一段,那么这个调用会进行排队依次执行。而就是只要当前面N次调用都完成以后,后面的调用才会进行。可以经过一下代码验证:
清空client.js的内容,不需要。 然后main.js的内容是:

var fs = Npm.require(‘fs’);
Meteor.methods({
“test”:function(a){
if(a==1){
//这里我通过多次读写文件的时间耗费进行阻塞
//,注意文件大小最好是在10M-40M之间,太小的文件,或者一般的计算可能执行速度太快看不到效果
for(var i=0;i<20;i++){
var data = fs.readFileSync(“/home/ec/download/NVIDIA”);
fs.writeFileSync(“/home/ec/download/test/NVIDIA”+i, data);
}
}
console.log(a);
}
});
在单个浏览器端,或者同时多个浏览器运行:(把命令写在一行)

Meteor.call(“test”,1); Meteor.call(“test”,2);
这样就可以看到阻塞的效果。[我猜大概这样是为了实现类似资源锁之类操作]

那么现在,我们不想它阻塞在这里也是很容易做的。没错!就是在函数的第一行执行:
(这里貌似存在一个bug 这个this.unblock()没有起作用 ,具体原因可参考 详情 和 解决方法)

this.unblock();
这是main.js内容如下:(参考解决过后的代码)

var fs = Npm.require(‘fs’);
var readFile = Meteor._wrapAsync(fs.readFile.bind(fs));
var writeFile = Meteor._wrapAsync(fs.writeFile.bind(fs));
Meteor.methods({
“test”:function(a){
this.unblock();
if(a==1){
//这里我通过多次读写文件的时间耗费进行阻塞
//,注意文件大小最好是在10M-40M之间,太小的文件,或者一般的计算可能执行速度太快看不到效果
var data = readFile(“/home/ec/download/NVIDIA”);
for(var i=0;i<5;i++){
writeFile(“/home/ec/download/test/NVIDIA”+i, data);
console.log(a+”-“+i);
}
}
console.log(a);
return a;
}
});
好了,this.unblock()的使用是这篇博客多耗费了2天时间。总算跳过去了。现在就剩最后一个点了。

this.connection Server
这是一个Connection对象,具体可以参考Server connections和这个部分的Meteor.onConnection(callback) 此属性不再本篇博客的讨论范围内。既然不讨论,那么就抄个官方文档的解释放在这里吧。

Access inside a method invocation. The connection this method was received on. null if the method is not associated with a connection, eg. a server initiated method call.

其中一个表达的大概意思是 如果没有通过http(非Client-Server或DDP)而是直接在Server中来调用这个methods里面的方法,那么connection是一个null。

本篇博客结束了。

对了最后其实还落下了一点点。那就是关于Meteor.apply(name, params [, options] [, asyncCallback])第三个可选参数options的解释了。
应该比较好理解 。同样贴上一个官方文档。

Options #仅在client端才有此参数
wait Boolean
(Client only) If true, don’t send this method until all previous method calls have completed, and don’t send any subsequent method calls until this one is completed.
onResultReceived Function
解释:如果为true,除非前面的方法调用都已经完成回调了,才会开始执行本次的函数调用。并且在本次函数调用完成之前 不会在执行其他任何的函数调用了。
(Client only) This callback is invoked with the error or result of the method (just like asyncCallback) as soon as the error or result is available. The local cache may not yet reflect the writes performed by the method.

这个的验证代码可以自己尝试写一下。就当是思考题吧。

转载请注明出处。谢谢!
————————————————
版权声明:本文为CSDN博主「ec_huyinghuan」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/a6383277/article/details/18098929/

Meteor应用的启动过程分析 - hoolev的个人页面 - OSCHINA - 中文开源技术交流社区

mikel阅读(620)

来源: Meteor应用的启动过程分析 – hoolev的个人页面 – OSCHINA – 中文开源技术交流社区

使用Meteor创建和运行一个应用是非常简单的,而简单的背后就是繁杂的细节。 我们希望通过分析源码,抽丝剥茧,来理解这简单背后的细节之美。

meteor v0.9.0.1

运行一个应用

首先我们得创建一个应用meteor create test,后面的代码分析都会用到这个应用。 在Meteor中只要在应用目录中执行meteor命令就可以运行这个应用了,应用正常运行之后会有如下打印:

[[[[[ ~/WCode/test ]]]]]
=> Started proxy.
=> Started your app. 
=> App running at: http://localhost:3000/

从上面的打印看Meteor先启动proxy、然后再启动app,但是在启动proxy之前应该还做了一些事的, 比如校验传入参数、获取环境变量、加载Package和Module等等。 根据上述推测,我们暂时把应用的启动过程分为四个步骤:环境配置、加载、启动proxy和启动app。

入口

当我们执行curl https://install.meteor.com/ | sh完成meteor安装之后, 系统中会出现一个/usr/local/bin/meteor可执行文件和一个~/.meteor/目录。 ~/.meteor/目录中包含了Meteor运行需要的所有脚本、包和模块。 /usr/local/bin/meteor这个Shell脚本做了两件事:

  • 检查Meteor是否成功安装,没有就重新安装一遍。
  • 运行~/.meteor/meteor

其实这个脚本执行了一次之后,就不需要再执行这个脚本了, 完全可以把~/.meteor/加入到$PATH中或者创建链接来直接执行~/.meteor/meteor

执行ls ~/.meteor/meteor -al这个命令就可以看到其实这只是个链接, 实际的文件是~/.meteor/packages/meteor-tool/1.0.26/meteor-tool-os.linux.x86_32/meteor

这也是个Shell脚本,也做了两件事:检查Meteor版本和运行exec "$DEV_BUNDLE/bin/node" "$METEOR" "$@" 其中DEV_BUNDLE="$SCRIPT_DIR/dev_bundle",METEOR="$SCRIPT_DIR/tools/main.js"$@是输入的命令和参数 而SRCIPT_DIR=~/.meteor/packages/meteor-tool/.1.0.26.13pjtg1++os.linux.x86_32+web.browser+web.cordova/meteor-tool-os.linux.x86_32/

因此,meteor运行的真正入口是main.js,这个文件在源码中位于tools目录下。

main.js

main.js中Fiber(function(){...}).run()类似于C语言中的main()函数,是所有函数的入口。 这个函数首先检查Node的版本和ROOT_URL,然后解析并校验传入的命令和参数,最后执行命令。 所有命令的实现在tools/command.js中,默认的命令是run。