金沙国际官网_金沙国际平台登录

因为这个金沙国际官网_金沙国际平台登录网站与很多的大型澳门赌场都有合作,金沙国际官网_金沙国际平台登录尽职尽责,高效执行,保持好奇心,不断学习,追求卓越,点击进入金沙国际官网_金沙国际平台登录马上体验吧,所以现在也正式地开始了营业。

您的位置:金沙国际官网 > web前端 > 渲染引擎介绍,记一次换行引发的血案

渲染引擎介绍,记一次换行引发的血案

发布时间:2019-11-07 04:52编辑:web前端浏览(147)

    记一次换行引发的血案

    2018/06/19 · 基础技术 · 换行

    原文出处: 怡红公子   

    话说最近真是流年不利,感觉各种BUG犹如天灾一样全部冒出来了,这不昨天又解了一个非常无语的问题,大概是关于换行和正则的臭虫,下面给大家吐槽一下。

    如何 hack Node.js 模块?

    2016/10/28 · JavaScript · NodeJS

    原文出处: 淘宝前端团队(FED)- 宣予   

    图片 1

    GCanvas 渲染引擎介绍

    2017/07/31 · HTML5 · Canvas

    原文出处: 淘宝前端团队(FED)- 韦青   

    图片 2

    GCanvas 提供了一套类似于 H5 Canvas 标准的 JavaScript API。基于这套 API 可以方便的去做图形绘制、动画渲染等,开发的体验与 H5 Canvas 是完全一样的。

    数据“野”了

    昨天同事反馈某个页面的数据没有正常显示,最开始我还以为是接口没有返回数据,结果看了下请求发现接口有正常的数据呀。没办法就一路反查回去,最后查到居然代码里接口请求抛错了?!因为定义了 Promise 的 catch 流程,所以也没有把错误抛出来。因为之前这个页面都是正常的,很久都没有改动所以我第一反应是这个数据异常了,查了半天的数据格式问题。可是问题就在于明明看到数据是正常的呀,服务端没有报错,接口数据也是可以正常解析的。最后我突然想起来,我们的接口是 JSONP 的会不会是 JSONP 功能挂了?查了一下果然是这样。

    图片 3

    我们都知道 JSONP 需要定义一个 callback 回调名称,最后数据加载的时候执行这个回调返回数据才算成功。可以看到图里面虽然加了 callback=? 但是并没有对 ? 进行替换,服务端那边应该也是增加了校验这种情况下并没有给我们添加回调方法名。实际上服务端这里的处理都是没问题的,因为即使 ? 被添加到数据里了也会有问题,因为 ? 是逻辑运算符并不能被定义成变量。而没有加回调方法的后果就是虽然接口返回正常,但是最终数据没有人接收就“野”了。

    为何要去 hack?

    在业务开发过程中,往往会依赖一些 Node.js 模块,hack 这些 Node.js 模块的主要目的是在不修改工具源码的情况下,篡改一些特定的功能。可能会是出于以下几种情况的考虑:

    1. 总是存在一些特殊的本地需求,不一定能作为工具的通用需求来暴露正常的 API 给更多的用户。
    2. 临时且紧急的需求,提 PR 已经来不及了。
    3. 为什么不直接去改源码?考虑到工具会不定期升级,想使用工具的最新特性,改源码可维护性太差。

    GCanvas 介绍

    GCanvas发展经历了两个阶段。

    • 第一阶段,2014 年中到 2015 年底,解决 Android 平台 WebView Canvas 渲染性能差的问题。
    • 第二阶段,2016 年 11 月到现在,为前端提供 Native 图形绘制能力。

    用一句话来概括 GCanvas,即遵循 W3C 标准,移动端的跨平台的高性能图形渲染引擎。可以从三个方面来解释。

    • 遵循 W3C 标准
      GCanvas 提供了一套类似于 H5 Canvas 标准的 JavaScript API,开发人员基于这套 API 可以方便的去做图形绘制、动画渲染等。开发的体验与 H5 Canvas 是完全一样的。
    • 跨平台
      GCanvas 的内核基于 OpenGL ES, 用 C++ 实现了一套用于描述 Canvas 标准 API 的接口实现。我们将其称为渲染引擎内核。并通过交叉编译,使得可以适配 Android、iOS 这两大主流移动平台,因而具有跨平台的特性。
    • 高性能
      早期移动平台上 H5 Canvas 去做一些复杂的动画或游戏,在 WebView 上的体验非常差。 主要原因是 WebView 对 GPU 硬件加速的支持差。高性能则是充分利用了 GPU 硬件的渲染能力,主要体现两个方面:
      • 对于 Android 3.0 以前的系统,Android 的渲染管线是不支持硬件加速的,WebView 中的 Canvas 不能获得 GPU 的图形渲染能力的支持。对于这类系统,通过 GCanvas 可以获得更底层的 OpenGL ES 的硬件加速能力提高渲染效率。
      • 链路上来看,缩短了调用路径,提高了渲染性能。使用了 GCanvas 则不需要经过 WebView 内部的复杂逻辑处理和图层树渲染,而是让 JavaScript 通过桥接方式直接调用渲染引擎内核(OpenGL ES)。

    我的回调呢?

    我们在内部是使用了 zepto 这个基础库的。由于添加回调方法名并做替换肯定是 zepto 内部的行为,所以当我查到这的时候我都懵了。难道一年难遇一次国际知名库的 BUG 就这样被我水逆的碰到了?怀着一脸惊讶的表情我打开了 zepto 的文件继续查了下去。最终我发现还真是 zepto 里面 callback=? 没有替换成功。定义好 callback 方法之后 zepto 里面是这么去替换接口地址的参数的:

    JavaScript

    // window[callbackName] = function(){ responseData = arguments } script.src = options.url.replace(/?(.+)=?/, '?$1=' + callbackName) document.head.appendChild(script)

    1
    2
    3
    4
    5
    6
    7
    // https://github.com/madrobby/zepto/blob/master/src/ajax.js#L121-L126
    window[callbackName] = function(){
      responseData = arguments
    }
     
    script.src = options.url.replace(/?(.+)=?/, '?$1=' + callbackName)
    document.head.appendChild(script)

    通过正则匹配到两个 ? 后并替换最后一个 ? 为回调方法名。最开始我一直没绕过来,我在想这特么是什么骚操作?能匹配到 callback=? 么??callback=? 是可以匹配到,万一这个东西在后面 &callback=? 不就挂了么?最后才反应过来它这么做是直接匹配了整个地址后的 query,忽略了参数名称直接匹配 ?。对于这种操作,我只能说:

    图片 4

    那么在当前的情况下这种操作会有什么问题呢,我怀着不服输的精神又查了下去。结果我发现在这种情况下这个正则居然跪了!最后我在这打印出来看,发现传进去的 URL 里面多了一个回车符,导致这段正则失效了。因为我们知道正则里面的 . 元字符是匹配除了回车符以外的所有字符。(这无语的BUG…果然水逆就算是啥也不干问题也会自动找上门啊…

    图片 5

    当我查到这的时候我就思考了两个问题:

    1. 这个回车从哪里来的?参数里怎么会有回车?因为这个参数是直接从当前页的 URL 获取的,所以是我们在拼接的时候操作的有问题,还是服务端下发的当前地址就有问题?
    2. 为什么到了最后 URL 地址这还有回车,正常情况下到这步的时候应该库都会对其进行转码编译了,例如回车符会被编成 %0A 这样其实 zepto 内部再处理就没有问题了呀?所以是哪里给漏编码了呢?

    期望

    举个栗子:

    JavaScript

    // a.js module.exports = function(){ dosomething(); } // b.js module.exports = require(a); // c.js console.log(require(b));

    1
    2
    3
    4
    5
    6
    7
    8
    // a.js
    module.exports = function(){
      dosomething();
    }
    // b.js
    module.exports = require(a);
    // c.js
    console.log(require(b));

    b 是项目 c 依赖的一个工具模块,b 依赖 a。希望只在项目 c 中,b 调用 a 时,a 的函数里能注入一些方法 injectSomething()

    • hack 之前 c 的输出

    JavaScript

    function(){ dosomething(); }

    1
    2
    3
    function(){
      dosomething();
    }
    • 期望:hack 之后 c 的输出

    JavaScript

    function(){ injectSomething(); dosomething(); }

    1
    2
    3
    4
    function(){
      injectSomething();
      dosomething();
    }

    具体案例比如:在做个人自动化工具时,需要 mock 一些工具的手动输入;在本地构建时,需要修改通用的构建流程(后面案例部分会详细说)

    GCanvas 组成

    图片 6

    如上图所示 GCanvas 由三层组成 JavaScript 层、插件层、核心渲染库。

    • JavaScript 层
      JavaScript 提供对外统一的 API,支持 Canvas 2D 和 WebGL 的功能接口。接口支持情况请参考 API 覆盖。
    • 插件层
      插件层核心包含三部分。
      • Bridge 桥接
        JavaScript 到 Native 的桥接,比较主流的方式 JSBridge 和 JSBinding。JSBridge 实现方式,如 Cordva、WebviewJavascriptBridge 等。 还可以用 JSBinding 方式来实现,如 V8、JavascriptCore 等。实际的应用场景中这两种桥接方式都有支持。
      • 通用插件
        通用插件包含了通用插件接口与实现、GCanvas 的管理、渲染命令队列管理、纹理缓存等。支持不同类型桥接方式下的扩展。
      • 系统适配
        系统适配涉及 Android 和 iOS 对 OpenGL ES 实现的差异,网络图片下载,字体渲染等方面。
    • 核心渲染库
      核心渲染库包括对外统一的接口,以及 Contex2D 和 WebGL 模块,底层则是对 OpenGL ES API 等分装。

    哪里来的回车符

    顺着上面两个问题,由于第一个问题的成本比较低,先看了下回车符哪里来的问题。我优先看了下当前地址,发现在当前地址的时候已经有问题了。而其他路径进入的这个页面都是正常的,只有这个特殊情况下有问题,遂反馈给服务端反查一下。最后服务端(PHP)那查到原来是因为他们读取文件时按行分割没有注意到方法里会带着换行的问题。

    大概就是服务端那会有一个 token 文件,里面按行记录着一堆 ID,服务端会使用 file() 读取这个文件,然后将每个 ID 都 map 成一个地址下发下去。使用 file() 的好处是它在读取文件的时候能自动输出一个按行分割后的数组,这样就不需要额外操作。不过服务端同学没有注意,PHP 文档里也非常清楚的写明了:

    Note:

    Each line in the resulting array will include the line ending, unless FILE_IGNORE_NEW_LINES is used, so you still need to use rtrim() if you do not want the line ending present.

    via: 

    也就是说这种方法默认分割后的数组每个数据是包含最后的那个换行符的!想要去掉换行符需要添加 FILE_IGNORE_NEW_LINES 的标记参数。我自己也试了下发现果真如此!可以看到数组的前三个里面字符串的长度都是 4。

    图片 7

    最后服务端从来源上解决了这个问题。

    主要方法

    GCanvas 流程

    图片 8

    上图是 JavaScript 层渲染核心库的概要流程,关键的两个流程是初始化和渲染。

    • 初始化
      初始化,JavaSript 层获取配置判断运行环境,通过桥接层,插件层完成视图和 GCanvas 的创建。进一步完成对 OpenGL 环境的初始化。
    • 渲染
      渲染,JavaScript 层将所有的API调用托管,并且转换成自定义的命令格式(命令类型 + 参数的组合)。渲染触发则由 JavaScript 定时器触发或者手动触发的方式,将这些命令下发到渲染核心库执行。

    以 Weex 为例, 绘制图形和图片的测试代码如下。

    JavaScript

    <template> <div ref="test"> <gcanvas ref="canvas_holder" style="width:750; height:750; background-color:rgba(0, 0, 0, 0.1)"></gcanvas> </div> </template> <script> var GCanvas=require('weex-gcanvas'); var Image=require('weex-gcanvas/gcanvasimage'); module.exports = { mounted: function () { //1、初始化 GCanvas var ref = this.$refs.canvas_holder; var gcanvas = GCanvas.start(ref); var ctx = gcanvas.getContext('2d'); //2、执行渲染操作 //rect ctx.fillStyle = 'red'; ctx.fillRect(0, 0, 100, 100); //rect ctx.fillStyle = 'black'; ctx.fillRect(100, 100, 100, 100); ctx.fillRect(25, 210, 700, 5); //circle ctx.arc(450, 200, 100, 0, Math.PI * 2, true); ctx.fill(); //drawImage var image = new Image(); image.onload = function(){ ctx.drawImage(image, 100, 330); ctx.drawImage(image, 100+300, 330, 225, 75); } image.src = ''; } }; </script>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    <template>
    <div ref="test">
    <gcanvas ref="canvas_holder" style="width:750; height:750; background-color:rgba(0, 0, 0, 0.1)"></gcanvas>
    </div>
    </template>
    <script>
    var GCanvas=require('weex-gcanvas');
    var Image=require('weex-gcanvas/gcanvasimage');
    module.exports = {
    mounted: function () {
      
      //1、初始化 GCanvas
    var ref = this.$refs.canvas_holder;
    var gcanvas = GCanvas.start(ref);
    var ctx = gcanvas.getContext('2d');
    //2、执行渲染操作
    //rect
    ctx.fillStyle = 'red';
    ctx.fillRect(0, 0, 100, 100);
     
    //rect
    ctx.fillStyle = 'black';
    ctx.fillRect(100, 100, 100, 100);
    ctx.fillRect(25, 210, 700, 5);
     
    //circle
    ctx.arc(450, 200, 100, 0, Math.PI * 2, true);
    ctx.fill();
     
    //drawImage
    var image = new Image();
    image.onload = function(){
    ctx.drawImage(image, 100, 330);
    ctx.drawImage(image, 100+300, 330, 225, 75);
    }
    image.src = 'https://www.khronos.org/assets/uploads/ceimg/made/assets/uploads/apis/OpenGL-ES_100px_May16_225_75.png';
    }
    };
    </script>

    通过 Weex Playground 运行结果如下

    图片 9

    具体分析下整个流程。结合插件层和核心渲染库来分析。

    • 插件层流程
      以 iOS 为例分析,Android 的过程是类似的。
      • GLKView 视图创建,并且与 GCanvas 对象建立绑定关系;
      • GCVCommon,资源加载与纹理绑定;
      • GCanvasPlugin,设置位置信息、设备比率、下发渲染命令;
    • 渲染库流程

    图片 10

    渲染命令的解析,最终通过调用 OpenGL ES 的方法或组合方法来实现 Context2D 和 WebGL 的效果,生成帧缓存,提交给 GPU 渲染,最后在绑定的 GLKView 视图上显示。

    • Context2D,需要实现诸如 GPath、GTexture、GTransform、GTriangulate 等来实现 Canvas 的渲染效果;
    • WebGL 相对简单,WebGL1.0 的 API 基本都能与从 OpenGL ES2.0 找到与之相对应的 API;

    为什么没被转义

    虽然问题解决了,但是我的第二个疑问其实还没有被解决。本来应该被转义的字符为什么没有被转义?是道德的沦丧还是人性的泯灭zepto 出问题了还是我们的代码里有什么潜在的风险?

    图片 11

    我先去检查了一下 zepto 自己本身,发现它们的所有数据拼接都没有问题,使用了 $.param() 方法,而该方法内是使用了 escape() 对键值都做了编码的。zepto 出问题是不可能的了,那只能是我自己代码里的问题了。回到业务代码里查了一圈,最后发现,在某个阴暗的角落,居然窝藏了这么一段代码:

    JavaScript

    data.topicListApi = location.protocol + `//imnerd.org/detail?u=${uid}&sign=${sign}&n=10&tid=${tid}${onlineTypeParam}${tagParam}${rawUrlParam}${topUrlParam}`;

    1
    data.topicListApi = location.protocol + `//imnerd.org/detail?u=${uid}&sign=${sign}&n=10&tid=${tid}${onlineTypeParam}${tagParam}${rawUrlParam}${topUrlParam}`;

    这一堆参数不经过任何编码就直接进行字符串拼接的操作…

    图片 12

    利用模块 cache 篡改模块对象属性

    这是我最早使用的方法,在模块 a 的类型是 object 的时候,可以在自己的项目 c 中提早 require 模块 a,按照你的需求修改一些属性,这样当模块 b 再去 require 模块 a 时,从缓存中取出的模块 a 已经是被修改过的了。

    模块 a、b、c 栗子如下:

    JavaScript

    // a.js module.exports = { p } // b.js const a = require(a); a.p(); // c.js require(b);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // a.js
    module.exports = {
      p
    }
    // b.js
    const a = require(a);
    a.p();
    // c.js
    require(b);

    我想修改 a 的方法 p,在 c 中进行如下修改即可,而无需直接去修改工具 a、b 的源码:

    JavaScript

    // c.js const a = require(a); let oldp = a.p; a.p = function(...args){ injectSomething(); oldp.apply(this, args); } require(b);

    1
    2
    3
    4
    5
    6
    7
    8
    // c.js
    const a = require(a);
    let oldp = a.p;
    a.p = function(...args){
       injectSomething();
       oldp.apply(this, args);
    }
    require(b);

    缺陷:在某些模块属性是动态加载的情况,不是那么灵敏,而且只能篡改引用对象。但大部分情况下还是能够满足需求的。

    GCanvas 测试例子

    下面给出一些 GCanvas 的案例。

    • GCanvas 与 H5 Canvas 性能对比

    图片 13

    • Android 平台,左边是 GCanvas,右边是 H5 Canvas。同屏渲染图片越多,性能差异越明显。
    • Hilo 2D
      100 条鱼基于 Hilo 2D 动画库,满屏鱼的动画测试。
    • Chart 图标渲染
      Chart 图标库的渲染效果基于图表库,不同类型的图表渲染测试。

    后记

    好啦,问题的来龙去脉前因后果总算是查清楚了。虽然这里面有各种坑,虽然服务端已经帮忙处理了,但是我明白最主要的问题还是最后的那个前段拼接的问题。所以我以血泪的历史告诉大家 URL 拼接一定要编码别搞什么骚操作啊!同时后面我 git blame 查了下写这个代码的同学,虽然离职了…但是我还是想…

    图片 14

    1 赞 收藏 评论

    图片 15

    修改require.cache

    在遇到模块暴露的是非对象的情况,就需要直接去修改 require 的 cache 对象了。关于修改 require.cache 的有效性,会在后面的原理部分详细说,先来简单的说下操作:

    JavaScript

    //a.js 暴露的非对象,而是函数 module.exports = function(){ doSomething(); } //c.js const aOld = require(a); let aId = require.resolve(aPath); require.cache[aId] = function(...args){ injectSomething(); aOld.apply(this, args); } require(b);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //a.js 暴露的非对象,而是函数
    module.exports = function(){
       doSomething();
    }
    //c.js
    const aOld = require(a);
    let aId = require.resolve(aPath);
    require.cache[aId] = function(...args){
       injectSomething();
       aOld.apply(this, args);
    }
    require(b);

    缺陷:可能后续调用链路会有人手动去修改 require.cache,例如热加载。

    附:GCanvas API 支持情况

    最后附上 GCanvas Contex2D 和 WebGLAPI 的支持列表,支持常用的接口。另外,WebGL 的 API 目前正在做补全开发,后续会支持 WebGL1.0 API 的全覆盖。

    • Context2D API
    API名称 API类型 状态
    fillStyle Attribute getter/setter Implemented
    strokeStyle Attribute getter/setter Empty
    shadowColor Attribute getter/setter Empty
    shadowBlur Attribute getter/setter Empty
    shadowOffsetX Attribute getter/setter Empty
    shadowOffsetY Attribute getter/setter Empty
    createLinearGradient() Method Empty
    createPattern() Method Empty
    createRadialGradient() Method Empty
    addColorStop() Method Empty
    isPointInPath() Method Empty
    createEvent() Method Empty
    toDataURL() Method Empty
    lineCap Attribute getter/setter Implemented
    lineJoin Attribute getter/setter Implemented
    lineWidth Attribute getter/setter Implemented
    miterLimit Attribute getter/setter Implemented
    font Attribute getter/setter Implemented
    textAlign Attribute getter/setter Implemented
    textBaseline Attribute getter/setter Implemented
    globalAlpha Attribute getter/setter Implemented
    globalCompositeOperation Attribute getter/setter Implemented
    rect() Method Implemented
    fillRect() Method Implemented
    strokeRect() Method Implemented
    clearRect() Method Implemented
    fill() Method Implemented
    stroke() Method Implemented
    beginPath() Method Implemented
    moveTo() Method Implemented
    closePath() Method Implemented
    lineTo() Method Implemented
    clip() Method Implemented
    quadraticCurveTo() Method Implemented
    bezierCurveTo() Method Implemented
    arc() Method Implemented
    arcTo() Method Implemented
    scale() Method Implemented
    rotate() Method Implemented
    translate() Method Implemented
    transform() Method Implemented
    setTransform() Method Implemented
    fillText() Method Implemented
    strokeText() Method Implemented
    measureText() Method Implemented
    drawImage() Method Implemented
    createImageData() Method Implemented
    getImageData() Method Implemented
    putImageData() Method Implemented
    save() Method Implemented
    restore() Method Implemented
    getContext() Method Implemented
    loadTexture() Method Implemented
    unloadTexture() Method Implemented
    resetTransform() Method Implemented
    render() Method Implemented
    capture() Method Implemented
    resetClip() Method Implemented
    • WebGL API
    API名称 API类型 状态
    viewport() Method Implemented
    vertexAttribPointer() Method Implemented
    vertexAttrib2fv() Method Implemented
    useProgram() Method Implemented
    uniformMatrix4fv() Method Implemented
    uniformMatrix3fv() Method Implemented
    uniformMatrix2fv() Method Implemented
    uniform4iv() Method Implemented
    uniform4i() Method Implemented
    uniform4fv() Method Implemented
    uniform4f() Method Implemented
    uniform3iv() Method Implemented
    uniform3i() Method Implemented
    uniform3fv() Method Implemented
    uniform3f() Method Implemented
    uniform2iv() Method Implemented
    uniform2i() Method Implemented
    uniform2fv() Method Implemented
    uniform2f() Method Implemented
    uniform1iv() Method Implemented
    uniform1i() Method Implemented
    uniform1fv() Method Implemented
    uniform1f() Method Implemented
    texParameteri() Method Implemented
    texImage2D() Method Implemented
    shaderSource() Method Implemented
    scissor() Method Implemented
    renderbufferStorage() Method Implemented
    pixelStorei() Method Implemented
    linkProgram() Method Implemented
    lineWidth() Method Implemented
    getUniformLocation() Method Implemented
    getShaderParameter() Method Implemented
    getAttribLocation() Method Implemented
    generateMipmap() Method Implemented
    frontFace() Method Implemented
    framebufferTexture2D() Method Implemented
    flush() Method Implemented
    enableVertexAttribArray() Method Implemented
    enable() Method Implemented
    drawElements() Method Implemented
    disableVertexAttribArray() Method Implemented
    disable() Method Implemented
    depthMask() Method Implemented
    depthFunc() Method Implemented
    deleteTexture() Method Implemented
    deleteShader() Method Implemented
    deleteRenderbuffer() Method Implemented
    deleteProgram() Method Implemented
    deleteFramebuffer() Method Implemented
    deleteBuffer() Method Implemented
    cullFace() Method Implemented
    createTexture() Method Implemented
    createShader() Method Implemented
    createRenderbuffer() Method Implemented
    createProgram() Method Implemented
    createFramebuffer() Method Implemented
    createBuffer() Method Implemented
    compileShader() Method Implemented
    colorMask() Method Implemented
    clearStencil() Method Implemented
    clearDepth() Method Implemented
    clearColor() Method Implemented
    clear() Method Implemented
    bufferData() Method Implemented
    blendFuncSeparate() Method Implemented
    blendFunc() Method Implemented
    blendEquationSeparate() Method Implemented
    blendEquation() Method Implemented
    bindRenderbuffer() Method Implemented
    bindFramebuffer() Method Implemented
    bindBuffer() Method Implemented
    bindAttribLocation() Method Implemented
    attachShader() Method Implemented
    activeTexture() Method Implemented
    validateProgram() Method Empty
    texSubImage2D() Method Empty
    texParameterf() Method Empty
    stencilOpSeparate() Method Empty
    stencilOp() Method Empty
    stencilMaskSeparate() Method Empty
    stencilMask() Method Empty
    stencilFuncSeparate() Method Empty
    stencilFunc() Method Empty
    sampleCoverage() Method Empty
    readPixels() Method Empty
    polygonOffset() Method Empty
    isTexture() Method Empty
    isShader() Method Empty
    isRenderbuffer() Method Empty
    isProgram() Method Empty
    isFramebuffer() Method Empty
    isEnabled() Method Empty
    isContextLost() Method Empty
    isBuffer() Method Empty
    getVertexAttribOffset() Method Empty
    getVertexAttrib() Method Empty
    getUniform() Method Empty
    getTexParameter() Method Empty
    getSupportedExtensions() Method Empty
    getShaderSource() Method Empty
    getShaderPrecisionFormat() Method Empty
    getShaderInfoLog() Method Empty
    getRenderbufferParameter() Method Empty
    getProgramParameter() Method Empty
    getProgramInfoLog() Method Empty
    getParameter() Method Empty
    getFramebufferAttachmentParameter() Method Empty
    getExtension() Method Empty
    getError() Method Empty
    getContextAttributes() Method Empty
    getBufferParameter() Method Empty
    getAttachedShaders() Method Empty
    getActiveUniform() Method Empty
    getActiveAttrib() Method Empty
    drawArrays / drawArraysInstancedANGLE() Method Empty
    detachShader() Method Empty
    depthRange() Method Empty
    copyTexSubImage2D() Method Empty
    copyTexImage2D() Method Empty
    compressedTexSubImage2D() Method Empty
    compressedTexImage2D() Method Empty
    checkFramebufferStatus() Method Empty
    bufferSubData() Method Empty
    blendColor() Method Empty
    bindTexture() Method Undefined
    commit() Method Undefined
    finish() Method Undefined
    framebufferRenderbuffer() Method Undefined
    hint() Method Undefined

    1 赞 1 收藏 评论

    图片 16

    修改 require

    这种方法是直接去代理 require ,是最稳妥的方法,但是侵入性相对来说比较强。Node.js 文件中的 require 其实是在 Module 的原型方法上,即 Module.prototype.require。后面会详细说,先简单说下操作:

    JavaScript

    const Module = require('module'); const _require = Module.prototype.require; Module.prototype.require = function(...args){ let res = _require.apply(this, args); if(args[0] === 'a') { // 只修改a模块内容 injectSomething(); } return res; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    const Module = require('module');
    const _require = Module.prototype.require;
    Module.prototype.require = function(...args){
        let res = _require.apply(this, args);
        if(args[0] === 'a') { // 只修改a模块内容
            injectSomething();
        }
        return res;
    }

    缺陷:对整个 Node.js 进程的 require 操作都具有侵入性。

    本文由金沙国际官网发布于web前端,转载请注明出处:渲染引擎介绍,记一次换行引发的血案

    关键词:

上一篇:static以及继承,前端开发基础

下一篇:没有了