区块链技术博客
www.b2bchain.cn

六、7. 事件循环机制求职学习资料

D0b2wT.gif

本文介绍了六、7. 事件循环机制求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。

对技术面试,学习经验等有一些体会,在此分享。

事件循环机制「Event Loop」,负责是整个 JavaScript 执行环境的代码执行顺序的问题。

准确的说,事件循环机制,是执行环境的机制,不是 JavaScript 的机制。函数调用栈是 JavaScript 的代码顺序机制。

在前面我们的章节已经学习到,如果没有异步事件,函数调用栈能够负责几乎所有的代码执行顺序问题。

但是异步事件的存在,让代码执行顺序变得更加复杂。

例如下面的例子

setTimeout(() => {   console.log('index 1') }, 1000)  console.log('index 2')

setTimeout 是一个很常见的异步事件。回调函数中的 index 1 并不会马上执行,而是要等到 1s 之后才会执行。

index 2 则会立即执行。

事件循环机制,就是异步事件代码执行顺序的解决方案。

线程

六、7. 事件循环机制

完整的理解事件循环机制,一定要对 JavaScript 执行环境的线程有非常清晰的认知。

JavaScript 是一个单线程的语言。

但是 JavaScript 的执行环境,是由多个线程协同工作的结果。不同的线程,对应着不同的异步事件。我们一一简单了解一下。

GUI 渲染线程

更详细的与性能有关的渲染知识,点击 https://xiaozhuanlan.com/topic/4203159786

GUI 负责浏览器界面 HTML 元素的渲染。

六、7. 事件循环机制

图中的样式规则,就是 CSSOM。

和常规的认知不同的是,DOM 的渲染过程,是异步的。

用一个简单的例子来验证这个结论。

<!DOCTYPE html> <html>  <head>   <meta charset="UTF-8">   <title>DOM 渲染是否异步</title> </head>  <body>   <div id="d">默认文本</div>   <script>     d.onclick = function () {       console.log('开始更改DOM')       this.innerHTML = "往div里添加的新文本";//更改一个节点       console.log('DOM 更改完毕')       document.body.appendChild(document.createElement("input"));//插入一个节点       for (var i = 0; i < 10000000000; i++);       console.log('xxxx')     }   </script> </body> </html>

这段代码的核心,是使用大数据量的 for 循环拉长 JavaScript 代码的执行时间,让执行步骤能够清晰的被感知。

用常规思维分析一下这段代码的执行顺序。

当我点击 div 时。按照顺序,执行过程应该如下

1. 打印 开始更改DOM 2. 修改 div 的文本内容为 "往div里添加的新文本" 3. 打印 DOM 更改完毕 4. 插入新的 input 节点 5. 循环 6. 打印 xxxx

可事实上并非如此。

验证一下,真实的执行顺序为

1. 打印 开始更改DOM 2. 打印 DOM 更改完毕 3. 循环 4. 打印 xxxx  // DOM 的渲染,实际上最后才执行 5. 修改 div 的文本内容为 "往div里添加的新文本" 6. 插入新的 input 节点

我们可以发现,UI 的渲染,明显滞后于代码的执行位置。

因此我们可以得出结论,UI 的渲染过程,与 setTimeout 类似,都被事件循环机制,放在了后面执行。

需要注意的是,div 的文本内容修改,是同步修改 DOM 的结构,但是 DOM 结构修改之后,并没有立刻渲染到页面中,这里是两个步骤。

场景:改变已经存在的 DOM

这里涉及到的更深层的问题,是对 DOM 的理解。DOM 本质是一个 JS 对象。因此操作 DOM 和渲染 DOM 是不同的。操作 DOM 本质上是操作 JavaScript 对象,这是同步的过程。渲染 DOM,是 GUI 线程来完成的工作,这是异步的。

DOM 跟 React 的虚拟 DOM,几乎是一样的逻辑。

JavaScript 引擎线程

浏览器并不能直接运行 JavaScript 代码。需要在浏览器中植入内核,为 JavaScript 的运行提供环境。chrome 中,这个内核就是 V8。

每一个网页进程,浏览器只会启动一个 JavaScript 引擎线程来配合完成网页的交互。

定时器线程

setTimeout、setInterval 的逻辑是由专门的定时器线程在负责。

写入定时器回调函数中的逻辑并不会立刻执行,即使我们将时间设置为 0.

setTimeout(() => {   console.log('定时器的回调逻辑') }, 0) console.log('代码的最后位置')   // 执行结果 // 代码的最后位置 // 定时器的回调逻辑

I/O 事件触发线程

当我们鼠标点击、滑动,键盘输入等都会触发一些事件。而这些事件的触发逻辑的处理,就是依靠事件触发线程来完成。

与上面的线程一样,该线程会把事件的逻辑放入队列之中,等待 JavaScript 引擎处理。

http 线程

http线程的主要作用,是使用无状态短连接的 http 请求,在应用层基于 http 协议的基础之上,达到与服务端进行通信的目的「在服务端,也会有专门的 http 线程来处理通信过程」。

当然,该线程的触发逻辑,事件监听等也不是在 JS 引擎线程中,这个过程仍然是异步的。

Promise

在浏览器中,线程对应的异步事件,并不能涵盖所有的异步事件类型。

Promise 就是一个特例。

Promise 是 JavaScript 的内部逻辑,并非由浏览器额外的线程来执行。因此,Promise 的异步逻辑与线程对应的异步逻辑是不一样的。

在 JavaScript 引擎的处理逻辑中,Promise 有自己的事件队列,并且该队列在所有 JavaScript 代码执行完成之后执行。

简单梳理一下 Promise 的队列扭转逻辑,该逻辑来源于 ECMAScript 标准。

现有简单的示例代码如下

// 创建一个 promise 实例 const p = new Promise((resolve, reject) => {})  p.then(f, r)

job

我们在 then 中添加的回调函数,就是一个 job。也就是此处的 f 与 r。catch 同理。

执行队列

ECMAScript 提供了一个用于存储 Promise 异步逻辑的队列 PromiseJobs

该队列中的逻辑在所有 JS 代码执行完之后执行。

状态

一个 promise 实例有三种状态,

  • pending:等待结果状态
  • fulfilled:已出结果,结果符合预期完成状态
  • rejected:已出结果,结果不符合预期完成状态

当一个 promise 实例创建时,初始处于 pending 状态。

pending 状态中,不会向 PromiseJobs 队列中加入任何 job。

当 resolve 函数调用时,pending -> fulfilled

当 reject 函数调用时,pending -> rejected

当 promise 的状态有了结果,不再是 pending,那么我们称该 promise 的状态被固定:settled。

何时进入队列 PromiseJobs

当代码中调用 p.then(f, r) 时,会将 job f 放入 [[PromiseFulfillReactions]] 队列尾部。将 job r 放入 [[PromiseRejectReactions]] 队列尾部。

此处的两个队列,是临时中间队列,该队列中的 job 只会移入到 PromiseJobs 队列中而不会有自己的执行过程。PromiseJobs 才有执行 job 的逻辑。

六、7. 事件循环机制

resolve/reject 调用,promise 状态产生了结果,此时会根据不同的结果:p.then(f, r),将不同的 job「f/r」 加入到 PromiseJobs 队列中。

如果在创建 promise 对象时,就已经 settled,那么 job 会直接进入到 PromiseJobs 队列中。

const p = new Promise((resolve, reject) => {   // 直接敲定状态   resolve() })

链式调用时,后续的 then 如何将 job 加入到 PromiseJobs 队列,需要根据上一个 then 的反馈结果来决定。

当不确定返回结果时,而 then 函数已经调用,那么,对应的 job 放入临时队列中。

已经确定了返回结果时,才会将 job 移入到 PromiseJobs 队列中。

PromiseJobs 队列如何执行

经过之前的知识,我们已经知道 job 何时进入 PromiseJobs 队列。那么进入队列之后,job 是如何执行的呢?

当然,队列的执行逻辑很简单,就是直接先进入的 job 先执行。但是这里有一个需要注意的地方在于,当 job 执行时,又会产生新的 job 进入到该队列。因此 PromiseJobs 在执行过程中会动态变化。

PromiseJobs 的执行有如下规则:

  1. 当所有的代码执行完毕,PromiseJobs 的队列开始出队执行。
  2. PromiseJobs 处于动态变化中,只有当 PromiseJobs 队列为空时,才会结束执行。即使 job 在执行过程中,产生了新 job 加入队列。

文字表达可能难以理解,我们可以用下面的代码来表达同样的含义

“`js
const PromiseJobs = []

let job

事件循环机制「Event Loop」,负责是整个 JavaScript 执行环境的代码执行顺序的问题。

准确的说,事件循环机制,是执行环境的机制,不是 JavaScript 的机制。函数调用栈是 JavaScript 的代码顺序机制。

在前面我们的章节已经学习到,如果没有异步事件,函数调用栈能够负责几乎所有的代码执行顺序问题。

但是异步事件的存在,让代码执行顺序变得更加复杂。

例如下面的例子

setTimeout(() => {   console.log('index 1') }, 1000)  console.log('index 2')

setTimeout 是一个很常见的异步事件。回调函数中的 index 1 并不会马上执行,而是要等到 1s 之后才会执行。

index 2 则会立即执行。

事件循环机制,就是异步事件代码执行顺序的解决方案。

线程

六、7. 事件循环机制

完整的理解事件循环机制,一定要对 JavaScript 执行环境的线程有非常清晰的认知。

JavaScript 是一个单线程的语言。

但是 JavaScript 的执行环境,是由多个线程协同工作的结果。不同的线程,对应着不同的异步事件。我们一一简单了解一下。

GUI 渲染线程

更详细的与性能有关的渲染知识,点击 https://xiaozhuanlan.com/topic/4203159786

GUI 负责浏览器界面 HTML 元素的渲染。

六、7. 事件循环机制

图中的样式规则,就是 CSSOM。

和常规的认知不同的是,DOM 的渲染过程,是异步的。

用一个简单的例子来验证这个结论。

<!DOCTYPE html> <html>  <head>   <meta charset="UTF-8">   <title>DOM 渲染是否异步</title> </head>  <body>   <div id="d">默认文本</div>   <script>     d.onclick = function () {       console.log('开始更改DOM')       this.innerHTML = "往div里添加的新文本";//更改一个节点       console.log('DOM 更改完毕')       document.body.appendChild(document.createElement("input"));//插入一个节点       for (var i = 0; i < 10000000000; i++);       console.log('xxxx')     }   </script> </body> </html>

这段代码的核心,是使用大数据量的 for 循环拉长 JavaScript 代码的执行时间,让执行步骤能够清晰的被感知。

用常规思维分析一下这段代码的执行顺序。

当我点击 div 时。按照顺序,执行过程应该如下

1. 打印 开始更改DOM 2. 修改 div 的文本内容为 "往div里添加的新文本" 3. 打印 DOM 更改完毕 4. 插入新的 input 节点 5. 循环 6. 打印 xxxx

可事实上并非如此。

验证一下,真实的执行顺序为

1. 打印 开始更改DOM 2. 打印 DOM 更改完毕 3. 循环 4. 打印 xxxx  // DOM 的渲染,实际上最后才执行 5. 修改 div 的文本内容为 "往div里添加的新文本" 6. 插入新的 input 节点

我们可以发现,UI 的渲染,明显滞后于代码的执行位置。

因此我们可以得出结论,UI 的渲染过程,与 setTimeout 类似,都被事件循环机制,放在了后面执行。

需要注意的是,div 的文本内容修改,是同步修改 DOM 的结构,但是 DOM 结构修改之后,并没有立刻渲染到页面中,这里是两个步骤。

场景:改变已经存在的 DOM

这里涉及到的更深层的问题,是对 DOM 的理解。DOM 本质是一个 JS 对象。因此操作 DOM 和渲染 DOM 是不同的。操作 DOM 本质上是操作 JavaScript 对象,这是同步的过程。渲染 DOM,是 GUI 线程来完成的工作,这是异步的。

DOM 跟 React 的虚拟 DOM,几乎是一样的逻辑。

JavaScript 引擎线程

浏览器并不能直接运行 JavaScript 代码。需要在浏览器中植入内核,为 JavaScript 的运行提供环境。chrome 中,这个内核就是 V8。

每一个网页进程,浏览器只会启动一个 JavaScript 引擎线程来配合完成网页的交互。

定时器线程

setTimeout、setInterval 的逻辑是由专门的定时器线程在负责。

写入定时器回调函数中的逻辑并不会立刻执行,即使我们将时间设置为 0.

setTimeout(() => {   console.log('定时器的回调逻辑') }, 0) console.log('代码的最后位置')   // 执行结果 // 代码的最后位置 // 定时器的回调逻辑

I/O 事件触发线程

当我们鼠标点击、滑动,键盘输入等都会触发一些事件。而这些事件的触发逻辑的处理,就是依靠事件触发线程来完成。

与上面的线程一样,该线程会把事件的逻辑放入队列之中,等待 JavaScript 引擎处理。

http 线程

http线程的主要作用,是使用无状态短连接的 http 请求,在应用层基于 http 协议的基础之上,达到与服务端进行通信的目的「在服务端,也会有专门的 http 线程来处理通信过程」。

当然,该线程的触发逻辑,事件监听等也不是在 JS 引擎线程中,这个过程仍然是异步的。

Promise

在浏览器中,线程对应的异步事件,并不能涵盖所有的异步事件类型。

Promise 就是一个特例。

Promise 是 JavaScript 的内部逻辑,并非由浏览器额外的线程来执行。因此,Promise 的异步逻辑与线程对应的异步逻辑是不一样的。

在 JavaScript 引擎的处理逻辑中,Promise 有自己的事件队列,并且该队列在所有 JavaScript 代码执行完成之后执行。

简单梳理一下 Promise 的队列扭转逻辑,该逻辑来源于 ECMAScript 标准。

现有简单的示例代码如下

// 创建一个 promise 实例 const p = new Promise((resolve, reject) => {})  p.then(f, r)

job

我们在 then 中添加的回调函数,就是一个 job。也就是此处的 f 与 r。catch 同理。

执行队列

ECMAScript 提供了一个用于存储 Promise 异步逻辑的队列 PromiseJobs

该队列中的逻辑在所有 JS 代码执行完之后执行。

状态

一个 promise 实例有三种状态,

  • pending:等待结果状态
  • fulfilled:已出结果,结果符合预期完成状态
  • rejected:已出结果,结果不符合预期完成状态

当一个 promise 实例创建时,初始处于 pending 状态。

pending 状态中,不会向 PromiseJobs 队列中加入任何 job。

当 resolve 函数调用时,pending -> fulfilled

当 reject 函数调用时,pending -> rejected

当 promise 的状态有了结果,不再是 pending,那么我们称该 promise 的状态被固定:settled。

何时进入队列 PromiseJobs

当代码中调用 p.then(f, r) 时,会将 job f 放入 [[PromiseFulfillReactions]] 队列尾部。将 job r 放入 [[PromiseRejectReactions]] 队列尾部。

此处的两个队列,是临时中间队列,该队列中的 job 只会移入到 PromiseJobs 队列中而不会有自己的执行过程。PromiseJobs 才有执行 job 的逻辑。

六、7. 事件循环机制

resolve/reject 调用,promise 状态产生了结果,此时会根据不同的结果:p.then(f, r),将不同的 job「f/r」 加入到 PromiseJobs 队列中。

如果在创建 promise 对象时,就已经 settled,那么 job 会直接进入到 PromiseJobs 队列中。

const p = new Promise((resolve, reject) => {   // 直接敲定状态   resolve() })

链式调用时,后续的 then 如何将 job 加入到 PromiseJobs 队列,需要根据上一个 then 的反馈结果来决定。

当不确定返回结果时,而 then 函数已经调用,那么,对应的 job 放入临时队列中。

已经确定了返回结果时,才会将 job 移入到 PromiseJobs 队列中。

PromiseJobs 队列如何执行

经过之前的知识,我们已经知道 job 何时进入 PromiseJobs 队列。那么进入队列之后,job 是如何执行的呢?

当然,队列的执行逻辑很简单,就是直接先进入的 job 先执行。但是这里有一个需要注意的地方在于,当 job 执行时,又会产生新的 job 进入到该队列。因此 PromiseJobs 在执行过程中会动态变化。

PromiseJobs 的执行有如下规则:

  1. 当所有的代码执行完毕,PromiseJobs 的队列开始出队执行。
  2. PromiseJobs 处于动态变化中,只有当 PromiseJobs 队列为空时,才会结束执行。即使 job 在执行过程中,产生了新 job 加入队列。

文字表达可能难以理解,我们可以用下面的代码来表达同样的含义

“`js
const PromiseJobs = []

let job

事件循环机制「Event Loop」,负责是整个 JavaScript 执行环境的代码执行顺序的问题。

准确的说,事件循环机制,是执行环境的机制,不是 JavaScript 的机制。函数调用栈是 JavaScript 的代码顺序机制。

在前面我们的章节已经学习到,如果没有异步事件,函数调用栈能够负责几乎所有的代码执行顺序问题。

但是异步事件的存在,让代码执行顺序变得更加复杂。

例如下面的例子

setTimeout(() => {   console.log('index 1') }, 1000)  console.log('index 2')

setTimeout 是一个很常见的异步事件。回调函数中的 index 1 并不会马上执行,而是要等到 1s 之后才会执行。

index 2 则会立即执行。

事件循环机制,就是异步事件代码执行顺序的解决方案。

线程

六、7. 事件循环机制

完整的理解事件循环机制,一定要对 JavaScript 执行环境的线程有非常清晰的认知。

JavaScript 是一个单线程的语言。

但是 JavaScript 的执行环境,是由多个线程协同工作的结果。不同的线程,对应着不同的异步事件。我们一一简单了解一下。

GUI 渲染线程

更详细的与性能有关的渲染知识,点击 https://xiaozhuanlan.com/topic/4203159786

GUI 负责浏览器界面 HTML 元素的渲染。

六、7. 事件循环机制

图中的样式规则,就是 CSSOM。

和常规的认知不同的是,DOM 的渲染过程,是异步的。

用一个简单的例子来验证这个结论。

<!DOCTYPE html> <html>  <head>   <meta charset="UTF-8">   <title>DOM 渲染是否异步</title> </head>  <body>   <div id="d">默认文本</div>   <script>     d.onclick = function () {       console.log('开始更改DOM')       this.innerHTML = "往div里添加的新文本";//更改一个节点       console.log('DOM 更改完毕')       document.body.appendChild(document.createElement("input"));//插入一个节点       for (var i = 0; i < 10000000000; i++);       console.log('xxxx')     }   </script> </body> </html>

这段代码的核心,是使用大数据量的 for 循环拉长 JavaScript 代码的执行时间,让执行步骤能够清晰的被感知。

用常规思维分析一下这段代码的执行顺序。

当我点击 div 时。按照顺序,执行过程应该如下

1. 打印 开始更改DOM 2. 修改 div 的文本内容为 "往div里添加的新文本" 3. 打印 DOM 更改完毕 4. 插入新的 input 节点 5. 循环 6. 打印 xxxx

可事实上并非如此。

验证一下,真实的执行顺序为

1. 打印 开始更改DOM 2. 打印 DOM 更改完毕 3. 循环 4. 打印 xxxx  // DOM 的渲染,实际上最后才执行 5. 修改 div 的文本内容为 "往div里添加的新文本" 6. 插入新的 input 节点

我们可以发现,UI 的渲染,明显滞后于代码的执行位置。

因此我们可以得出结论,UI 的渲染过程,与 setTimeout 类似,都被事件循环机制,放在了后面执行。

需要注意的是,div 的文本内容修改,是同步修改 DOM 的结构,但是 DOM 结构修改之后,并没有立刻渲染到页面中,这里是两个步骤。

场景:改变已经存在的 DOM

这里涉及到的更深层的问题,是对 DOM 的理解。DOM 本质是一个 JS 对象。因此操作 DOM 和渲染 DOM 是不同的。操作 DOM 本质上是操作 JavaScript 对象,这是同步的过程。渲染 DOM,是 GUI 线程来完成的工作,这是异步的。

DOM 跟 React 的虚拟 DOM,几乎是一样的逻辑。

JavaScript 引擎线程

浏览器并不能直接运行 JavaScript 代码。需要在浏览器中植入内核,为 JavaScript 的运行提供环境。chrome 中,这个内核就是 V8。

每一个网页进程,浏览器只会启动一个 JavaScript 引擎线程来配合完成网页的交互。

定时器线程

setTimeout、setInterval 的逻辑是由专门的定时器线程在负责。

写入定时器回调函数中的逻辑并不会立刻执行,即使我们将时间设置为 0.

setTimeout(() => {   console.log('定时器的回调逻辑') }, 0) console.log('代码的最后位置')   // 执行结果 // 代码的最后位置 // 定时器的回调逻辑

I/O 事件触发线程

当我们鼠标点击、滑动,键盘输入等都会触发一些事件。而这些事件的触发逻辑的处理,就是依靠事件触发线程来完成。

与上面的线程一样,该线程会把事件的逻辑放入队列之中,等待 JavaScript 引擎处理。

http 线程

http线程的主要作用,是使用无状态短连接的 http 请求,在应用层基于 http 协议的基础之上,达到与服务端进行通信的目的「在服务端,也会有专门的 http 线程来处理通信过程」。

当然,该线程的触发逻辑,事件监听等也不是在 JS 引擎线程中,这个过程仍然是异步的。

Promise

在浏览器中,线程对应的异步事件,并不能涵盖所有的异步事件类型。

Promise 就是一个特例。

Promise 是 JavaScript 的内部逻辑,并非由浏览器额外的线程来执行。因此,Promise 的异步逻辑与线程对应的异步逻辑是不一样的。

在 JavaScript 引擎的处理逻辑中,Promise 有自己的事件队列,并且该队列在所有 JavaScript 代码执行完成之后执行。

简单梳理一下 Promise 的队列扭转逻辑,该逻辑来源于 ECMAScript 标准。

现有简单的示例代码如下

// 创建一个 promise 实例 const p = new Promise((resolve, reject) => {})  p.then(f, r)

job

我们在 then 中添加的回调函数,就是一个 job。也就是此处的 f 与 r。catch 同理。

执行队列

ECMAScript 提供了一个用于存储 Promise 异步逻辑的队列 PromiseJobs

该队列中的逻辑在所有 JS 代码执行完之后执行。

状态

一个 promise 实例有三种状态,

  • pending:等待结果状态
  • fulfilled:已出结果,结果符合预期完成状态
  • rejected:已出结果,结果不符合预期完成状态

当一个 promise 实例创建时,初始处于 pending 状态。

pending 状态中,不会向 PromiseJobs 队列中加入任何 job。

当 resolve 函数调用时,pending -> fulfilled

当 reject 函数调用时,pending -> rejected

当 promise 的状态有了结果,不再是 pending,那么我们称该 promise 的状态被固定:settled。

何时进入队列 PromiseJobs

当代码中调用 p.then(f, r) 时,会将 job f 放入 [[PromiseFulfillReactions]] 队列尾部。将 job r 放入 [[PromiseRejectReactions]] 队列尾部。

此处的两个队列,是临时中间队列,该队列中的 job 只会移入到 PromiseJobs 队列中而不会有自己的执行过程。PromiseJobs 才有执行 job 的逻辑。

六、7. 事件循环机制

resolve/reject 调用,promise 状态产生了结果,此时会根据不同的结果:p.then(f, r),将不同的 job「f/r」 加入到 PromiseJobs 队列中。

如果在创建 promise 对象时,就已经 settled,那么 job 会直接进入到 PromiseJobs 队列中。

const p = new Promise((resolve, reject) => {   // 直接敲定状态   resolve() })

链式调用时,后续的 then 如何将 job 加入到 PromiseJobs 队列,需要根据上一个 then 的反馈结果来决定。

当不确定返回结果时,而 then 函数已经调用,那么,对应的 job 放入临时队列中。

已经确定了返回结果时,才会将 job 移入到 PromiseJobs 队列中。

PromiseJobs 队列如何执行

经过之前的知识,我们已经知道 job 何时进入 PromiseJobs 队列。那么进入队列之后,job 是如何执行的呢?

当然,队列的执行逻辑很简单,就是直接先进入的 job 先执行。但是这里有一个需要注意的地方在于,当 job 执行时,又会产生新的 job 进入到该队列。因此 PromiseJobs 在执行过程中会动态变化。

PromiseJobs 的执行有如下规则:

  1. 当所有的代码执行完毕,PromiseJobs 的队列开始出队执行。
  2. PromiseJobs 处于动态变化中,只有当 PromiseJobs 队列为空时,才会结束执行。即使 job 在执行过程中,产生了新 job 加入队列。

文字表达可能难以理解,我们可以用下面的代码来表达同样的含义

“`js
const PromiseJobs = []

let job

部分转自互联网,侵权删除联系

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » 六、7. 事件循环机制求职学习资料
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们