威尼斯人线上娱乐

【威尼斯人线上娱乐】报料浏览器远程调节和测试本领,中对Node程序进行调节和测试

26 4月 , 2019  

揭发浏览器远程调节和测试才干

2016/10/19 · 基础技能 ·
1 评论 ·
浏览器,
调试,
远程

最初的文章出处: Tmall前端团队(FED) –
肖焉   

威尼斯人线上娱乐 1

威尼斯人线上娱乐 2

简介

chrome-remote-interface是chrome调节和测试协议的第2方调整客户端完结,该品种开源,提供了命令行工具,且为node程序提供了api。
chrome-remote-interface为依靠chrome调节和测试协议编写本人的node调试工具提供了简便的渠道,因为使用它,你不要求依照原始的协商通过websocket编制程序去付出调节和测试工具了。
品类地址https://github.com/cyrus-and/chrome-remote-interface。

启动node.js脚本

$ NODE_ENV=production API_KEY=442CC1FE-4333-46CE-80EE-6705A1896832
node server.js

调度本领的来源于

1九4九 年 玖 月 玖 日,一名美利坚联邦合众国的化学家格蕾丝.霍普和他的同伴在对 马克 II
计算机举办研讨的时候开采,二头飞蛾粘在一个继电器上,导致计算机不只怕不荒谬干活,当他俩把飞蛾移除之后,Computer又卷土重来了例行运营。于是他们将那只飞蛾贴在了她们当即记下的日记上,对那件事情举办了详实的笔录,并在日记最终写了那般一句话:First
actual case of bug being found。那是她们发觉的率先个真正含义上的
bug,那也是全人类Computer软件历史上,发掘的首先个
bug,而她们找到飞蛾的点子和进程,正是 debugging 调节和测试技艺。

威尼斯人线上娱乐 3

从格蕾丝调试首个 bug 到目前,6玖年的光阴里,在处理器领域,硬件、软件种种调解才干都在持续的提高和多变。那么对于新生事物正在蓬勃发展的前端来讲,调节和测试技艺也更为显得首要。Tmall前端团队也正值利用一些翻新的才具和手法来减轻有线页面调节和测试的主题材料。昨日先跟大家分享下浏览器远程调试才干,本文将用
Chrome/Webview 来作为案例。

Node

采纳命令行

Node.js 控制台 REPL

在终极敲node进入repl

1+1
a = 1;

调解原理

深信有众几个人和本人同一,习于旧贯了采纳chrome调试js程序,然则node刚开头提供的调节和测试情势只用Debugger,只能通过node
–debug
xxx.js运营命令行调节和测试工具,及其的不便于。当然也有部分插件在此基础上,使用websocket实行通讯,使其能够在chrome浏览器中调养。体验和向来在chrome上海展览中心开调整依然差了过多。

安装

透过npm举行设置

npm install chrome-remote-interface

基础知识

Node.js是建立在谷歌 Chrome V8引擎和ECMASCLX570IPT之上的。

调理情势与权力管理

威尼斯人线上娱乐 4

当前例行浏览器调节和测试目的分为二种:Chrome PC 浏览器和 Chrome
Mobile(Android 4.四 未来,Android WebView 其实正是 Chromium WebView)。

可是在Node v七.x.x后,Node有提供了一个Inspector,可以直接和Chrome
DevTools进行通讯,上面来详细介绍进入调节和测试的手续,以及在使用进程中,小编遭逢的主题素材及化解办法。

启航调节和测试目标

chrome-remote-interface基于chrome调试协议,因而其援救调节和测试chrome浏览器和node运营条件。
任凭哪类调节和测试目的,其运维时都应该钦点调节和测试端口。
假定要调治chrome浏览器,应该在起步chrome时加多–remote-debugging-port参数,如下:

goole-chrome --remote-debugging-port=9222

举例调试node,在运营时加多–inspect参数,如下:

node --inspect=9222 app.js

此时,node会输出:

Debugger listening on port 9222.
Warning: This is an experimental feature and could change at any time.
To start debugging, open the following URL in Chrome:
    chrome-devtools://devtools/remote/serve_file/@60cd6e859b9f557d2312f5bf532f6aec5f284980/inspector.html?experiments=true&v8only=true&ws=localhost:9222/2894362d-f2d1-4f3b-a9e8-4e27da5714ef

题外话:借使只是希望调节和测试node,并不打算开垦三个调治node的工具以来,依照提示中的url,在chrome中展开就一向可以用chrome的开辟工具调试了。

命名

静态变量或然个人函数以_开头

Chrome PC 浏览器

对此调节和测试 Chrome PC
浏览器,或然大家经常使用的是用鼠标右键或许急速格局(mac:option + command

  • J),唤起 Chrome
    的调节台,来对脚下页面实行调度。其实还有其余一种格局,正是应用一个Chrome 浏览器调节和测试另1个 Chrome 浏览器。Chrome
    运营的时候,私下认可是关闭了调治端口的,假诺要对三个对象 Chrome PC
    浏览器实行调节和测试,那么运营的时候,可以因此传递参数来拉开 Chrome
    的调治开关:

JavaScript

# for mac sudo /Applications/Google\
Chrome.app/Contents/MacOS/Google\ Chrome –remote-debugging-port=9222

1
2
# for mac
sudo /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome –remote-debugging-port=9222

目录

  1. 具体调节和测试步骤详细介绍
  2. 难点及缓慢解决情势
  3. 别的工具
  4. 连带文书档案

体验命令行

  • 查看全数发令

    在顶峰输入chrome-remote-interface并回车,可观察如下输出:

Usage: chrome-remote-interface [options] [command]

Commands:

inspect [options] [<target>] inspect a target (defaults to the current tab)
list                   list all the available tabs
new [<url>]            create a new tab
activate <id>          activate a tab by id
close <id>             close a tab by id
version                show the browser version
protocol [options]     show the currently available protocol descriptor

Options:

-h, --help         output usage information
-t, --host <host>  HTTP frontend host
-p, --port <port>  HTTP frontend port
```

其中,new和close是针对浏览器的tab的命令,不要针对node来运行。
  • 翻看全体页面实例

    chrome-remote-interface -t 127.0.0.1 -p 9222 list

    出口如下:

    [ { description: 'node.js instance',
    devtoolsFrontendUrl: 'https://chrome-devtools-frontend.appspot.com/serve_file/@60cd6e859b9f557d2312f5bf532f6aec5f284980/inspector.html?experiments=true&v8only=true&ws=localhost:9222/2894362d-f2d1-4f3b-a9e8-4e27da5714ef',
    faviconUrl: 'https://nodejs.org/static/favicon.ico',
    id: '2894362d-f2d1-4f3b-a9e8-4e27da5714ef',
    title: 'app.js',
    type: 'node',
    url: 'file:///Users/renbaogang/git/enzyme.node/app.js',
    webSocketDebuggerUrl: 'ws://localhost:9222/2894362d-f2d1-4f3b-a9e8-4e27da5714ef' } ]
    

    中间devtoolsFrontendUrl能够在chrome地址栏中回车该url,张开chrome的开垦工具,能够直接用该工具调节和测试。和起步node时,node提醒的url是1个用场。
    id是日前页面标志。
    url是目前页面url。
    webSocketDebuggerUrl是node提供的ws协议的调治服务,调节和测试客户端要求经过该url连接受调节和测试服务。

  • 查阅调节和测试目标版本

    chrome-remote-interface -t 127.0.0.1 -p 9222 version

    输出:

    [ { Browser: 'node.js/v7.0.0', 'Protocol-Version': '1.1' } ]
    
  • 翻开调节和测试目的援助的调治协议

    chrome-remote-interface -t 127.0.0.1 -p 9222 protocol

    输出:

    { 
    remote: false,
    descriptor: {
        { version: { major: '1', minor: '2' },
        domains:[略]
    }
    }
    

    remote:false表明协议内容是工具自带的情商文件,并不是来自调节和测试目的。
    设若要博取调试目标的说道内容要拉长-r选项,如:

    chrome-remote-interface -t 127.0.0.1 -p 9222 protocol -r

    输出:

    { 
    remote: true,
    descriptor: {
        { version: { major: '1', minor: '1' },
        domains:[略]
    }
    }
    
  • 调整命令

    chrome-remote-interface -t 127.0.0.1 -p 9222 inspect -r
    -r 代表应用调节和测试目的提供的商谈描述文件
    因而inspect能够调解node或chrome所支撑的各个域。

    Console域体验

Console.enable()
{ result: {} }
Console.clearMessages()
{ result: {} }
“`

Debugger域体验

```

Debugger.enable()
{ result: {} }
Debugger.setBreakpointsActive({active:true})
{ result: {} }
“`

HeapProfiler域体验

```

HeapProfiler.enable()
{ result: {} }
HeapProfiler.startTrackingHeapObjects({trackAllocations:true})
{ result: {} }
“`

Profiler域体验

```

Profiler.enable()
{ result: {} }
Profiler.start()
{ result: {} }
Profiler.stop()
{ result:
{ profile:
{ nodes:
[ { id: 1,
callFrame:
{ functionName: ‘(root)’,
scriptId: ‘0’,
url: ”,
lineNumber: -1,
columnNumber: -1 },
hitCount: 0,
children: [ 2 ] },

      ]
    }
 }

}
“`

Runtime域体验  

>>> Runtime.evaluate({expression:"1+1"})
{ result: { result: { type: 'number', value: 2, description: '2' } } }

Schema域体验

>>> Schema.getDomains()
{ result: 
   { domains: 
      [ { name: 'Runtime', version: '1.1' },
        { name: 'Debugger', version: '1.1' },
        { name: 'Profiler', version: '1.1' },
        { name: 'HeapProfiler', version: '1.1' },
        { name: 'Schema', version: '1.1' } ] } }
    ```

    体验事件处理

    scriptParsed是Debugger域提供的脚本解析事件

    ```
>>> Debugger.scriptParsed(params=>params.url)
{ 'Debugger.scriptParsed': 'params=>params.url' }
{ 'Debugger.scriptParsed': '' }
{ 'Debugger.scriptParsed': '/Users/renbaogang/git/enzyme.node/node_modules/negotiator/lib/encoding.js' }
    ```

## API ##
1. module([options], [callback])

    基于chrome调试协议连接调试目标

    options object类型,具有如下属性:  
    - host 默认localhost
    - port 默认9222
    - chooseTab 决定调试哪个tab。该参数可以为三种类型:
        - function 提供一个返回tab序号的函数
        - object 正如new 和 list返回的对象一样
        - string websocket url
        默认为一个函数,返回当前激活状态的tab的序号,如:function(tabs){return 0;}
    - protocol 协议描述符,默认由remote选项来定是否使用调试目标提供的协议描述符
    - remote 默认false,如果protocol设置了,该选项不会起作用

  callback   
    如果callback是函数类型,则该函数在connect事件发生后会得到回调,并返回EventEmitter对象,如果不是,则返回Promise对象。

    EventEmitter对象支持如下事件:  

    - connect

        ```
    function (chrome) {}
    ```
    当websocket连接建立后触发,chrome是Chome类型的实例。

    - disconnect

        ```
        function () {}
        ```
        关闭websocket连接时触发

    - error

        ```
        function (err) {}
        ```
    当通过host:port/json无法到达,或websocket连接无法建立时触发  
        err,Error类型的错误对象

  使用样例,针对chrome浏览器:

    ```
const Chrome = require('chrome-remote-interface');
Chrome(function (chrome) {
    with (chrome) {
        Network.requestWillBeSent(function (params) {
            console.log(params.request.url);
        });
        Page.loadEventFired(function () {
            close();
        });
        Network.enable();
        Page.enable();
        once('ready', function () {
            Page.navigate({'url': 'https://github.com'});
        });
    }
}).on('error', function (err) {
    console.error('Cannot connect to Chrome:', err);
});
    ```

2. module.Protocol([options],[callback])

    获取chrome调试协议描述符

    options object类型,具有如下属性:  
    - host 默认localhost
    - port 默认9222
    - remote 默认false

    callback 回调函数,在获取到协议内容后调用,函数接收如下参数:  
    - err Error一个错误对象,如果有错误的话
    - protocol 包含以下属性
        - remote 是否远程协议
        - descriptor chrome调试协议描述符

  使用样例:

    ```
const Chrome = require('chrome-remote-interface');
Chrome.Protocol(function (err, protocol) {
    if (!err) {
        console.log(JSON.stringify(protocol.descriptor, null, 4));
    }
});
    ```

3. module.List([options], [callback])

    获取所有的tabs,当然在node中只会有一个  

    options object类型,具有如下属性:  
    - host 默认localhost
    - port 默认9222
    - remote 默认false

    callback 回调函数,在获取到tabs内容后调用,函数接收如下参数:  
    - err Error一个错误对象,如果有错误的话
    - tabs 获取到的tab数组

  使用样例:

    ```
const Chrome = require('chrome-remote-interface');
Chrome.List(function (err, tabs) {
    if (!err) {
        console.log(tabs);
    }
});
    ```

4. module.New([options], [callback])

    创建新的tab

    options object类型,具有如下属性:  
    - host 默认localhost
    - port 默认9222
    - url 新tab加载的url 默认about:blank

    callback 回调函数,在新tab创建后调用,函数接收如下参数:  
    - err Error一个错误对象,如果有错误的话
    - tab 新增的tab

  使用样例:  

    ```
const Chrome = require('chrome-remote-interface');
Chrome.New(function (err, tab) {
    if (!err) {
        console.log(tab);
    }
});
  1. module.Activate([options], [callback])

    激活钦命tab

    options object类型,具备如下属性:

    • host 默认localhost
    • port 默认9222
    • id 目标tab的id

    callback 回调函数,在新tab成立后调用,函数接收如下参数:

    • err Error叁个荒谬对象,假如有荒唐的话

接纳样例:

```

const Chrome = require(‘chrome-remote-interface’);
Chrome.Activate({‘id’: ‘CC46FBFA-3BDA-493B-B2E4-2BE6EB0D97EC’}, function
(err) {
if (!err) {
console.log(‘success! tab is closing’);
}
});
“`

  1. module.Close([options], [callback])

    关闭钦赐tab

    options object类型,具备如下属性:

    • host 默认localhost
    • port 默认9222
    • id 目标tab的id

    callback 回调函数,在新tab创办后调用,函数接收如下参数:

    • err Error八个张冠李戴对象,要是有错误的话

运用样例:

```

const Chrome = require(‘chrome-remote-interface’);
Chrome.Close({‘id’: ‘CC46FBFA-3BDA-493B-B2E4-2BE6EB0D97EC’}, function
(err) {
if (!err) {
【威尼斯人线上娱乐】报料浏览器远程调节和测试本领,中对Node程序进行调节和测试。console.log(‘success! tab is closing’);
}
});
“`

  1. module.Version([options], [callback])

    获取版本音讯

    options object类型,具备如下属性:

    • host 默认localhost
    • port 默认9222

    callback 回调函数,在新tab开创后调用,函数接收如下参数:

    • err Error3个错误对象,倘使有错误的话
    • info json object

使用样例:

```

const Chrome = require(‘chrome-remote-interface’);
Chrome.Version(function (err, info) {
if (!err) {
console.log(info);
}
});
“`

  1. Chrome 类

    支撑的轩然大波:

    • event

      在长距离调节和测试目标发送公告时接触,一般是远程对象实行了客户端提交的法门后

      function (message) {}
      

      message包罗如下属性:

      • method 文告内容,方法名 如:’Network.request威尔BeSent’
      • params 参数内容

    运用样例:

     ```
     chrome.on('event', function (message) {
         if (message.method === 'Network.requestWillBeSent') {
             console.log(message.params);
         }   
     });
     ```
    
    • <method>

      调弄整理目的通过websocket发送了一个钦命方法名的通报

      function (params) {}
      

      应用样例:

      chrome.on('Network.requestWillBeSent', console.log);
      
    • ready

      老是未有调节和测试命令等待调节和测试目的重临时接触

      function () {}
      

      行使样例:

      只在Network和Page激活后加载二个url

      chrome.Network.enable();
      chrome.Page.enable();
      chrome.once('ready', function () {
          chrome.Page.navigate({'url': 'https://github.com'});
      });
      

支撑的章程

  • chrome.send(method, [params], [callback])

      发送一个调试命令
    
      method 命令名称  
      params 参数  
      callback 当远程对象对该命令发送一个应答后调用,函数具有以下参数:  
      - error boolean 是否成功
      - response 如果error===true,返回一个error对象,{error:...},否则返回一个应答,{result:...}
    
      注意:在chrome调试规范里提到的id字段,在这里被内部管理不会暴露给用户
    

    使用样例:

      ```
      chrome.send('Page.navigate', {'url': 'https://github.com'}, console.log);
      ```
    
    • chrome..([params], [callback])

      是chrome.send(‘.‘, params, callback);的一种变形

      例如:

        chrome.Page.navigate({'url': 'https://github.com'}, console.log);
      
    • chrome..(callback)

      是chrome.on(‘.‘, callback)的变形

      例如:

        chrome.Network.requestWillBeSent(console.log);
      
    • chrome.close([callback])

      关闭与远程调节和测试目标的连天
      callback会在websocket关闭成功后调用

保留的最主要词

  1. process
  2. global
  3. module.exports

Chrome Android 浏览器

对此调节和测试 Android 上的 Chrome 可能 WebView 需求接二连三 USB
线。展开调试端口的方法如下:

JavaScript

adb forward tcp:9222 localabstract:chrome_devtools_remote

1
adb forward tcp:9222 localabstract:chrome_devtools_remote

跟 Chrome PC 浏览器分裂的是,对于 Chrome Android
浏览器,由于数量传输是由此 USB 线而不是 WIFI,实际上 Chrome Android
创设的贰个 chrome_devtools_remote 那个 path 的 domain
socket。所以,上面一条命令则是经过 Android 的 adb 将 PC 的端口 922二 通过
USB 线与 chrome_devtools_remote 那个 domain socket
建立了二个端口映射。

现实调节和测试步骤详细介绍

__dirname和process.cwd 相对路径 要是像那样起步 $ node ./code/program.js.

互相的路径是差异等的

权限管理

谷歌(Google) 为了限制调节和测试端口的衔接范围,对于 Chrome PC
浏览器,调节和测试端口只接受来自 127.0.0.1 或者 localhost
的数量请求,所以,你不能够通过你的本地机械 IP 来调解 Chrome。对于 Android
Chrome/WebView,调节和测试端口只接受来自于 shell
那几个用户数量请求,也便是说只可以通过 USB 进行调解,而不可能因此 WIFI。

1. Chrome DevTools和Node版本必要

  1. Chrome DevTools: 55+
    在地点栏中输入chrome://settings/help,查看Chrome版本

    威尼斯人线上娱乐 5

    Chroem版本

  2. Node.js: v7.x.x+
    在命令行中输入node –version打开查看

    威尼斯人线上娱乐 6

    Node.js版本

骨干模块

  1. htpp
  2. util
  3. querystring
  4. url
  5. fs
  6. path
  7. crypto
  8. string_decoder

开班调节和测试

透过以上的调度格局的连接以及调度端口的展开,这一年在浏览器中输入:

JavaScript

1
http://127.0.0.1:9222/json

将会看到类似上面包车型地铁内容:

JavaScript

[ { “description”: “”, “devtoolsFrontendUrl”:
“/devtools/inspector.html?ws=1贰七.0.0.壹:9222/devtools/page/ebdace60-d48贰-4340-b62二-a61玖八e7aad6e”,
“id”: “ebdace60-d4八二-4340-b62二-a61玖八e柒aad陆e”, “title”:
“揭秘浏览器远程调节和测试才能.mdown—/Users/harlen/Documents”, “type”: “page”,
“url”: “”, “webSocketDebuggerUrl”:
“ws://127.0.0.1:9222/devtools/page/ebdace60-d482-4340-b622-a6198e7aad6e”
} ]

1
2
3
4
5
6
7
8
9
10
11
[
  {
    "description": "",
    "devtoolsFrontendUrl": "/devtools/inspector.html?ws=127.0.0.1:9222/devtools/page/ebdace60-d482-4340-b622-a6198e7aad6e",
    "id": "ebdace60-d482-4340-b622-a6198e7aad6e",
    "title": "揭秘浏览器远程调试技术.mdown—/Users/harlen/Documents",
    "type": "page",
    "url": "http://127.0.0.1:51004/view/61",
    "webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/page/ebdace60-d482-4340-b622-a6198e7aad6e"
  }
]

其间,最重大的 二 个参数分别是 id 和 webSocketDebuggerUrl。Chrome
会为种种页面分配1个唯一的
id,作为该页面包车型地铁唯一标记符。大概对指标浏览器的兼具操作都以供给带上这么些id。

Chrome 提供了以下这几个 http 接口调整目的浏览器

JavaScript

# 获取当前持有可调式页面新闻 # 获取调节和测试目标WebView/blink 的版本号 # 制造新的
tab,并加载 url # 关闭 id 对应的 tab

1
2
3
4
5
6
7
8
9
10
11
# 获取当前所有可调式页面信息
http://127.0.0.1:9222/json
 
# 获取调试目标 WebView/blink 的版本号
http://127.0.0.1:9222/json/version
 
# 创建新的 tab,并加载 url
http://127.0.0.1:9222/json/new?url
 
# 关闭 id 对应的 tab
http://127.0.0.1:9222/json/close/id

webSocketDebuggerUrl 则在调整该页面须要使用的1个 WebSocket 连接。chrome
的 devtool 的持有调节和测试成效,都是基于 Remote Debugging
Protocol
使用 WebSocket 来拓展多少传输的。那么那么些 WebSocket,就是地点我们从
http://127.0.0.1:9222/json 获取的
webSocketDebuggerUrl,每二个页面都有自身差别的
webSocketDebuggerUrl。这个 webSocketDebuggerUrl是透过 url 的 query
参数字传送递给 chrome devtool 的。

chrome 的 devtool 能够从 Chrome 浏览器中举行提取 devtool 源码或许从
blink 源码中收获。在配备好和煦的 chrome devtool
代码之后,上边既能够开端对 Chrome 举办调护医治, 浏览器输入一下剧情:

JavaScript

1
http://path_to_your_devtool/devtool.html?ws=127.0.0.1:9222/devtools/page/ebdace60-d482-4340-b622-a6198e7aad6e

内部 ws 那一个参数的值就是下面现身的 webSocketDebuggerUrl。Chrome 的
devtool 会使用那些 url 创造 WebSocket 对该页面进行调节和测试。

贰. 运行脚本,并走访调节和测试页面

完全步调:先依据具体境况,选择差别的参数运转脚本;然后访问相应的url获取调节和测试页面包车型客车拜访地址;最终访问那个地址,进入调护治疗页面。

在指令行中运转相应脚本,使用–inspect,或者–inspect-brk翻开调节和测试按键,如node
–inspect path/xxx.js
或者node –inspect-brk
path/xxx.js
。下边依照不相同意况张开具体分析。

调试node.js程序

  1. Node.js Debugger 并不佳用
  2. Node Inspector Chrome devtools的二个端口
  3. Webstrom IDE调节和测试 至极好用
  4. console.log

什么样达成 JavaScript 调节和测试

在进入 Chrome 的 devtool 之后,我们得以调出调节台,来查阅 devtool 的
WebSocket 数据。那一个里面有为数不少数目,作者那边只讲跟 JavaScript
调试相关的。
威尼斯人线上娱乐 7

图中,对于 JavaScript 调节和测试,有一条十分关键的消息,作者暗蓝选中的那条音讯:

JavaScript

{“id”:6,”method”:”Debugger.enable”}

1
{"id":6,"method":"Debugger.enable"}

然后选中要调度的 JavaScript 文件,然后设置1个断点,大家再来看看
WebSocket 音讯:
威尼斯人线上娱乐 8

devtool 像目标 Chrome 发送了 2 条消息

JavaScript

{ “id”: 23, “method”: “Debugger.getScriptSource”, “params”: {
“scriptId”: “103” } }

1
2
3
4
5
6
7
{
  "id": 23,
  "method": "Debugger.getScriptSource",
  "params": {
    "scriptId": "103"
  }
}

JavaScript

{ “id”: 24, “method”: “Debugger.setBreakpointByUrl”, “params”: {
“lineNumber”: 2, “url”:
“”,
“columnNumber”: 0, “condition”: “” } }

1
2
3
4
5
6
7
8
9
10
{
  "id": 24,
  "method": "Debugger.setBreakpointByUrl",
  "params": {
    "lineNumber": 2,
    "url": "https://g.alicdn.com/alilog/wlog/0.2.10/??aplus_wap.js,spm_wap.js,spmact_wap.js",
    "columnNumber": 0,
    "condition": ""
  }
}

那么收到这几条音信随后,V八 做了些什么吧?
大家先来大约的看下 V捌 里面的一小段源码片段:

JavaScript

// V8 Debugger.cpp DispatcherImpl(FrontendChannel* frontendChannel,
Backend* backend) : DispatcherBase(frontendChannel),
m_backend(backend) { m_dispatchMap[“Debugger.enable”] =
&DispatcherImpl::enable; m_dispatchMap[“Debugger.disable”] =
&DispatcherImpl::disable;
m_dispatchMap[“Debugger.setBreakpointsActive”] =
&DispatcherImpl::setBreakpointsActive;
m_dispatchMap[“Debugger.setSkipAllPauses”] =
&DispatcherImpl::setSkipAllPauses;
m_dispatchMap[“Debugger.setBreakpointByUrl”] =
&DispatcherImpl::setBreakpointByUrl;
m_dispatchMap[“Debugger.setBreakpoint”] =
&DispatcherImpl::setBreakpoint;
m_dispatchMap[“Debugger.removeBreakpoint”] =
&DispatcherImpl::removeBreakpoint;
m_dispatchMap[“Debugger.continueToLocation”] =
&DispatcherImpl::continueToLocation;
m_dispatchMap[“Debugger.stepOver”] = &DispatcherImpl::stepOver;
m_dispatchMap[“Debugger.stepInto”] = &DispatcherImpl::stepInto;
m_dispatchMap[“Debugger.stepOut”] = &DispatcherImpl::stepOut;
m_dispatchMap[“Debugger.pause”] = &DispatcherImpl::pause;
m_dispatchMap[“Debugger.resume”] = &DispatcherImpl::resume;
m_dispatchMap[“Debugger.searchInContent”] =
&DispatcherImpl::searchInContent;
m_dispatchMap[“Debugger.setScriptSource”] =
&DispatcherImpl::setScriptSource;
m_dispatchMap[“Debugger.restartFrame”] =
&DispatcherImpl::restartFrame;
m_dispatchMap[“Debugger.getScriptSource”] =
&DispatcherImpl::getScriptSource;
m_dispatchMap[“Debugger.setPauseOnExceptions”] =
&DispatcherImpl::setPauseOnExceptions;
m_dispatchMap[“Debugger.evaluateOnCallFrame”] =
&DispatcherImpl::evaluateOnCallFrame;
m_dispatchMap[“Debugger.setVariableValue”] =
&DispatcherImpl::setVariableValue;
m_dispatchMap[“Debugger.setAsyncCallStackDepth”] =
&DispatcherImpl::setAsyncCallStackDepth;
m_dispatchMap[“Debugger.setBlackboxPatterns”] =
&DispatcherImpl::setBlackboxPatterns;
m_dispatchMap[“Debugger.setBlackboxedRanges”] =
&DispatcherImpl::setBlackboxedRanges; }

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
// V8 Debugger.cpp
DispatcherImpl(FrontendChannel* frontendChannel, Backend* backend) : DispatcherBase(frontendChannel), m_backend(backend) {
    m_dispatchMap["Debugger.enable"] = &DispatcherImpl::enable;
    m_dispatchMap["Debugger.disable"] = &DispatcherImpl::disable;
    m_dispatchMap["Debugger.setBreakpointsActive"] = &DispatcherImpl::setBreakpointsActive;
    m_dispatchMap["Debugger.setSkipAllPauses"] = &DispatcherImpl::setSkipAllPauses;
    m_dispatchMap["Debugger.setBreakpointByUrl"] = &DispatcherImpl::setBreakpointByUrl;
    m_dispatchMap["Debugger.setBreakpoint"] = &DispatcherImpl::setBreakpoint;
    m_dispatchMap["Debugger.removeBreakpoint"] = &DispatcherImpl::removeBreakpoint;
    m_dispatchMap["Debugger.continueToLocation"] = &DispatcherImpl::continueToLocation;
    m_dispatchMap["Debugger.stepOver"] = &DispatcherImpl::stepOver;
    m_dispatchMap["Debugger.stepInto"] = &DispatcherImpl::stepInto;
    m_dispatchMap["Debugger.stepOut"] = &DispatcherImpl::stepOut;
    m_dispatchMap["Debugger.pause"] = &DispatcherImpl::pause;
    m_dispatchMap["Debugger.resume"] = &DispatcherImpl::resume;
    m_dispatchMap["Debugger.searchInContent"] = &DispatcherImpl::searchInContent;
    m_dispatchMap["Debugger.setScriptSource"] = &DispatcherImpl::setScriptSource;
    m_dispatchMap["Debugger.restartFrame"] = &DispatcherImpl::restartFrame;
    m_dispatchMap["Debugger.getScriptSource"] = &DispatcherImpl::getScriptSource;
    m_dispatchMap["Debugger.setPauseOnExceptions"] = &DispatcherImpl::setPauseOnExceptions;
    m_dispatchMap["Debugger.evaluateOnCallFrame"] = &DispatcherImpl::evaluateOnCallFrame;
    m_dispatchMap["Debugger.setVariableValue"] = &DispatcherImpl::setVariableValue;
    m_dispatchMap["Debugger.setAsyncCallStackDepth"] = &DispatcherImpl::setAsyncCallStackDepth;
    m_dispatchMap["Debugger.setBlackboxPatterns"] = &DispatcherImpl::setBlackboxPatterns;
    m_dispatchMap["Debugger.setBlackboxedRanges"] = &DispatcherImpl::setBlackboxedRanges;
}

你会发觉,V八 有 m_dispatchMap 那样八个 Map。专门用来管理所有JavaScript 调节和测试相关的拍卖。
其间就有本文将要入眼讲述的:

  • Debuggger.enable
  • Debugger.getScriptSource
  • setBreakpointByUrl

这个都急需在 V捌 的源码中找到答案。顺便给大家推荐三个查看 Chromium/V八最正确的法子是利用
https://cs.chromium.org,比 SourceInsight
还要便宜。

情况1

先是运营脚本,倘诺你的剧本搭建http或许net服务器,你能够一向运用–inspect。如

let net = require('net');

// 创建一个net服务器
const server = net.createServer();

// 连接回调函数
server.on('connection', (conn) => {
    console.log('connection');
});

// 监听8080端口
server.listen(8080);

// 监听回调函数
server.on('listening', () => {
    console.log('listening')
});

威尼斯人线上娱乐 9

运用–inspect后显示结果

注:

  1. 上海图书馆是在v8.玖.一版本时显得的结果,前边会一次列举出其它版本下的结果。
  2. Debugger listening on
    ws://127.0.0.1:9229/890b7b49-c744-4103-b0cd-6c5e8036be95,在那之中给定的url并不是提须要大家在Chrome浏览器中做客的地点,而是Node.js和Chrome之间进行通讯的的地址,它们经过websocket通过点名的端口举行通讯,从而将调节和测试结果实时突显在Chrome浏览器中。

然后,访问http://IP:port/json/list(当中IP就是主机的IP地址,平时为1贰7.0.0.1,port则是端口号,默以为922玖,这是Node提要求自由调解工具链接调节和测试的协议,能够由此命令行参数举行修改参数文书档案地址),会回去相应http请求的元数据,包罗WebSocket
UPRADOL,UUID,Chrome DevTools U科雷傲L。个中,WebSocket
URL
即使Node.js和Chrome之间的通讯地点;UUID是三个特定的标记,每3个经过都会分配二个uuid,因而每一遍调用会有出现不相同的结果;Chrome
DevTools URL
正是我们的调节和测试页面包车型地铁url。

如访问http://127.0.0.1:9229/json/list,大家将会博得一下结果,在那之中devtoolsFrontendUrl正是我们供给拜访的地方。

威尼斯人线上娱乐 10

显示屏快速照相 2017-1一-22 14.3四.一叁.png

末段,访问那么些地点后呈现页面:

威尼斯人线上娱乐 11

调治页面

使用Node.js Debugger

node debug hello.js

next 飞快键n 跳到下二个言辞
cont 火速键c 跳到下3个断点
step s 进入function
out o 跳出function
watch

开发浏览器

要么试行 curl

Debugger.enable

JavaScript

void V8Debugger::enable() { if (m_enableCount++) return;
DCHECK(!enabled()); v8::HandleScope scope(m_isolate);
v8::Debug::SetDebugEventListener(m_isolate,
&V8Debugger::v8DebugEventCallback, v8::External::New(m_isolate, this));
m_debuggerContext.Reset(m_isolate,
v8::Debug::GetDebugContext(m_isolate)); compileDebuggerScript(); }

1
2
3
4
5
6
7
8
9
void V8Debugger::enable() {
    if (m_enableCount++) return;
    DCHECK(!enabled());
    v8::HandleScope scope(m_isolate);
    v8::Debug::SetDebugEventListener(m_isolate, &V8Debugger::v8DebugEventCallback,
    v8::External::New(m_isolate, this));
    m_debuggerContext.Reset(m_isolate, v8::Debug::GetDebugContext(m_isolate));
    compileDebuggerScript();
}

其一接口的称呼叫 Debugger.enable,不过接到那条新闻,V8其实就干了两件事情事情:

  • SetDebugEventListener:
    给 JavaScript 调节和测试安装监听器,并安装 v8DebugEventCallback
    这一个回调函数。JavaScript
    全体的调解事件,都会被这几个监听器捕获,包涵:JavaScript
    十分结束,断点结束,单步调节和测试等等。
  • compileDebuggerScript:
    编译 V8 内置的 JavaScript 文件
    debugger-script.js。由于这文件比较长,笔者那边就不贴出来了,感兴趣的同学点击这么些链接进行查看源码。debugger-script.js
    首若是概念了一些对准 JavaScript
    断点进行操作的函数,比如设置断点、查找断点以及单步调节和测试相关的函数。那么那几个
    debugger-script.js 文件,被 V8 进行编写翻译之后,保存在 global
    对象上,等待对 JavaScript 实行调试的时候,被调用。

    #### Debugger.getScriptSource

    在 Chrome 解析引擎解析到 ` 标签之后,Chrome 将会把 script
    标签对应的 JavaScript 源码扔给 V8 编译执行。同时,V8 将会对所有的
    JavaScript 源码片段进行编号并保存。所以,当 chrome devtool
    需要获取要调试的 JavaScript 文件的时候,只需要通过
    Debugger.getScriptSource,给 V8 传递一个 scriptId,V8 将会把
    JavaScript 源码返回。我们再回头看看这个图中的消息:
    ![](http://jbcdn2.b0.upaiyun.com/2016/10/cc8205b6b73c6aa787046a0a6c634ae7.png)
    上面 id 为 23 的
    scriptSource` 就是 V8 重临的 JavaScript
    源码,如此的话,大家就可以在 devtool 中看看我们要调度的 JavaScript
    源码了。

情况2(重要)

倘使您的本子运转完未来直接结束进度,那么你须求采用–inspect-brk来运维调节和测试器,这样使得脚本能够代码实践从前break,不然,整个代码间接运营到代码结尾,甘休进程,根本不或许进行调和。如:

function sayHi(name) {
    console.log('Hello, ' + name);
}

sayHi('yyp');
  1. 使用–inspect:

    威尼斯人线上娱乐 12

    向来利用–inspect

向来行使–inspect,代码试行完成后,进程平昔结束,由此并未艺术在张开调和。

  1. 使用–inspect-brk:

    威尼斯人线上娱乐 13

    使用–inspect-brk

威尼斯人线上娱乐 14

访问127.0.0.1:9229

威尼斯人线上娱乐 15

调解页面

从下面叁张图中能够见见,此时该Node进度并不曾一贯退出,并且大家能够通过走访http://127.0.0.1:9229/json/list获得页面url,并且在调度页面中大家也发掘,程序在第一行break。

全面包车型大巴您,可能还开掘,与大家所写的程序分化的是,调节和测试页面中,将大家的顺序包裹在1个函数中,因为浏览器中不设有对应的对象(实际原因能够活动去商量)。

使用Node Inspector

npm install -g node-inspector

然后,启动node-inspector
node-inspector

在新的终点打开
node —debug-brk hello-debug.js or node —debug hello-debug.js

开拓chrome浏览器 其余浏览器不可能

Debugger.setBreakpointByUrl

装有筹算干活都办好了,将来就足以起来安装断点了。从地方的多少个图中,已经足以很理解的见到,Debugger.setBreakpointByUrl
给目标 Chrome 传递了二个 JavaScript 的 url 和断点的行号。

先是,V八 会去找,是或不是早已存在了该 UHighlanderL 对应的 JavaScript 源码了:

JavaScript

for (const auto& script : m_scripts) { if (!matches(m_inspector,
script.second->sourceURL(), url, isRegex)) continue;
std::unique_ptr<protocol::Debugger::Location> location =
resolveBreakpoint( breakpointId, script.first, breakpoint,
UserBreakpointSource); if (location)
(*locations)->addItem(std::move(location)); } *outBreakpointId =
breakpointId;

1
2
3
4
5
6
7
8
9
for (const auto& script : m_scripts) {
  if (!matches(m_inspector, script.second->sourceURL(), url, isRegex))
    continue;
  std::unique_ptr<protocol::Debugger::Location> location = resolveBreakpoint(
    breakpointId, script.first, breakpoint, UserBreakpointSource);
  if (location) (*locations)->addItem(std::move(location));
}
 
*outBreakpointId = breakpointId;

V八 给持有的断点,创立3个 breakpointObject。并将这个 braekpointObject 以
的样式存放在三个 Map 里面,而那个 Key,就是以此 JavaScript 文件的
URAV4L。看到此间,已经能够解释大多同校在调整 JavaScript
遭受的2个难题:,>

有个别同学为了卫戍页面包车型客车 JavaScript 文件不改进,对于部分首要的
JavaScript 文件的 U讴歌ZDXL 增添访问时间戳,对于这一个增添了走访时间戳的
JavaScript 文件举办设置断点然后刷新调节和测试的时候,Chrome 会打字与印刷二个warnning,告诉您断点丢失。

由来很简短,在调节和测试的时候,V捌 开采那些 breakpointMap 里面找不到对应的
breakpointObject,因为 UKoleosL 产生了变通,这一个 brakpointObject
就不见了,所以 V捌 就找不到了,不可能进展断点调节和测试。

依附大家的健康思维,你只怕会感觉 V八 会将断点设置在 C++
中,其实一初步自己也是这么认为。随着对 V8的研究,让小编看看了自家时曾相识的部分函数名:

JavaScript

v8::Local<v8::Function> setBreakpointFunction =
v8::Local<v8::Function>::Cast( m_debuggerScript.Get(m_isolate)
->Get(context, toV8StringInternalized(m_isolate, “setBreakpoint”))
.ToLocalChecked()); v8::Local<v8::Value> breakpointId =
v8::Debug::Call(debuggerContext(), setBreakpointFunction, info)
.ToLocalChecked();

1
2
3
4
5
6
7
v8::Local<v8::Function> setBreakpointFunction = v8::Local<v8::Function>::Cast(
    m_debuggerScript.Get(m_isolate)
    ->Get(context, toV8StringInternalized(m_isolate, "setBreakpoint"))
      .ToLocalChecked());
v8::Local<v8::Value> breakpointId =
  v8::Debug::Call(debuggerContext(), setBreakpointFunction, info)
    .ToLocalChecked();

其中,m_debuggerScript,就是本身前面提到的 debugger-script.js。随着对
V8 Debugger 的越发追究,笔者发觉,V八 实际上对这几个对那一个 breakpointObject
设置了 二 次。贰遍是透过在 C++ 中调用 m_debuggerScript 的 setBreakpoint
设置到 JavaScript 的 context 里面,也便是地点那段 C++
逻辑做的事情。另3回是,m_debuggerScript 反过来将断点音信设置到了 V8的 C++ Runtime 中,为要调整的 JavaScript 的某一行设置1个 JavaScript
的回调函数。

其余工具

node-inspector
在运用这几个工具从前,我一贯在行使node-inspector,只供给采取npm install -g
node-inspector安装node-inspector命令行工具,然后在采用node-inspector
path/xxx.js就可以运行调节和测试。
不足之处:调度体验相比差,绝对Chrome
DevTools使用,感到不够流畅,并且在较高版本中,debugger被撇下(v7.七.0+),进而不也许使用,恐怕会报错(v8.玖.一版本直接报错)。

vsCode + webStorm
提供第3手调节和测试功效(未使用过)。

检查实验文件退换

  1. forever
  2. nodemon
  3. supervisor
  4. up

断点命中

鉴于 V8 对 JavaScript 是及时编写翻译推行的,未有生成
bytecode,而是直接生成的 machine code
实行的,所以这几个断点回调函数也会被装置到那么些 machine code 里面。

最终触发断点事件,也是 V8 的 C++ Runtime。当用户刷新大概直接实行JavaScript 的逻辑的时候,实际上是 V八 C++ Runtime 在运转 JavaScript
片段发生的 machine code,那几个 machine code
已经包罗了断点回调函数了。壹旦那一个 machine code
里面包车型客车回调函数被触发,接着就会接触从前 Debugger.enable
设置的调节和测试事件监听器 Debug伊芙ntListener 的回调函数。并回到一条音信给
Chrome 的 devtool,告诉 Chrome devtool,当前 JavaScript 被 pause
的行号。到此停止,一个断点就被打中了。

有关 JavaScript
断点命中,其实是叁个很复杂的进程。后边有时光的话,会特地讲讲 JavaScript
断点命中的详细逻辑。

题材及缓和格局

总结

浏览器的调养,最后都落脚到引擎:渲染引擎和 JavaScipt 引擎。那么对于
JavaScript 调节和测试来说,难题就在于 V8 怎样给 JavaScript
某1行进行标志然后开展断点,那亟需有有些 V八 的知识。

2 赞 3 收藏 1
评论

威尼斯人线上娱乐 16

一. 互连网守旧的不合时宜设置方法走访地址

威尼斯人线上娱乐 17

老式设置格局

出现的标题,正是依据上述步骤操作之后,大家并未意识Node
debugging的选项,此时,就不知道什么开始展览下去了。在此间给出的表达是,在新式版的Chrome浏览器中,Node
debugging不必要手动去运营了,而是暗中同意就是可以运用的

威尼斯人线上娱乐,一. 分歧Node版本出现的难点

个别在八个大学本科子下进展了测试(v陆.九.二,v七.三.0,v捌.玖.一)

v陆.玖.贰 版本下使用状态

威尼斯人线上娱乐 18

命令行实行结果

威尼斯人线上娱乐 19

访问

那时候您会发掘,命令行已经给你拜访Chrome的url,并且这一个url和走访http://127.0.0.1:9229/json/list得到的devtoolsFrontendUrl属性值同样,然而,当您拜访这些url时,浏览器却不能够显得调节和测试页面,此时,表明你的Node版本太低,须要选取更加高版本。

v七.三.0 版本下行使情况

威尼斯人线上娱乐 20

命令行实施结果

威尼斯人线上娱乐 21

访问

威尼斯人线上娱乐 22

调解页面

那会儿,命令行也提供了访问调节和测试页面包车型地铁链接。

v八.九.1 版本下使用状态

威尼斯人线上娱乐 23

命令行实践结果

威尼斯人线上娱乐 24

访问

威尼斯人线上娱乐 25

调治页面

这时候,命令行给定的的url并不是调和页面包车型大巴url,因而必须通过访问http://127.0.0.1:9229/json/list来获得调节和测试页面url。

连锁文档

Debugging
Guide
Debugging Node.js
Apps


相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图