A reusable scatter plot inspired by Towards Reusable Charts and Observable: selection.join.
Shows the Iris Dataset.
A vanilla HTML implementation of a D3 scatter plot. Shows the Iris Dataset.
<script src='...d3'></script>
<body>
<script>
const { csv } = d3; //对ES6更加简便?
// const csv = d3.csv;
csv(csvUrl).then(data => {
console.log(data);
})
</body>
这段代码使用了JavaScript的Promise对象的 then() 方法。
Promise 对象是一个代表异步操作完成或失败的对象。 then() 方法 是 Promise 对象上的一个方法,用于注册一个回调函数。
在这个例子中:
csv(csvUrl) 返回一个 Promise 对象,代表从 csvUrl 获取数据 的异步操作。
在 then() 方法中,我们注册了一个回调函数,该函数会在Promise 对象成功完成(即异步操作成功)时被调用。
回调函数接收一个参数 data,该参数就是 Promise 对象 resolve 时传递的数据。在这个例子中,data 应该包含了从 csvUrl 获取 到的 CSV 数据。
最后,回调函数将 data 输出到控制台 (console.log(data))。
总之,这段代码演示了如何使用 Promise 对象和 then() 方法来处理 异步操作,比如从远程 CSV 文件中获取数据。Promise 对象是 JavaScript 中用于处理异步操作的一种机制。它代表一个异步操作 的最终完成(或失败)及其结果值。
Promise 对象有以下特点:
三种状态:
状态改变:
then() 方法:
链式调用:
使用 Promise 对象可以让异步代码变得更加清晰和易于管理。相比 于传统的回调函数方式,Promise 提供了更好的错误处理和状态跟踪 机制。
总之,Promise 对象是一种强大的异步编程模式,帮助开发者更好地组 织和控制异步代码的流程。
在这段代码中,使用了 async/await 语法,而不是 Promise 的then() 方法。这是因为:
async/await 语法是 ES2017 (ES8) 引入的新特性,用于简化异步 代码的编写和使用。
async 函数会自动返回一个 Promise 对象,而 await 关键字可以 等待 Promise 对象的结果。
在 main() 函数中,使用 await 关键字等待 csv(csvUrl, parseRow) 这个异步操作完成,获取到数据。这比使用 then() 方 法更加简洁和直观。
那么 then() 方法在什么时候使用呢?
一般来说, then() 方法适用于以下情况:
当你需要处理非 Promise 对象返回的异步操作时,比如使用回调 函数的场景。
当你需要对 Promise 对象的结果进行链式操作时,比如依次执行 多个异步操作。
当你需要处理 Promise 对象的错误时,可以在 then() 方法后面 添加 catch() 方法。
相比之下,async/await 语法在处理单个异步操作时更加简洁和易 读。但对于更复杂的异步流程,使用 Promise 的 then() 方法仍然是 一个好的选择。
总之,二者是并存的,开发者可以根据具体需求选择合适的方式来处理 异步操作。
好的,让我更详细地解释一下这里为什么要使用异步(async/await)。
在这个例子中,main()
函数使用异步的方式加载数据是为了确保在
绘制图表之前数据已经准备就绪。具体来说:
csv(csvUrl, parseRow)
是一个异步操作,它需要从远程获取数
据,这可能需要一些时间。如果不使用异步,这个操作可能会阻塞
整个程序的执行。
async
关键字将main()
定义为一个异步函数,这允许它使
用await
关键字等待 csv(csvUrl, parseRow)
操作完成。
await
关键字暂停了main()
函数的执行,直到
csv(csvUrl, parseRow)
返回数据为止。这确保了在绘制图表
之前,数据已经完全加载好了。
所以这里的async
和await
并不是函数,而是JavaScript的关键字,
用于定义和控制异步函数的执行流程。这种异步编程模式可以帮助程
序更好地管理I/O密集型操作,如网络请求,而不会阻塞整个程序的执
行。总的来说,使用异步编程模式能够提高应用程序的响应性和性能,
这在处理需要从远程获取数据的场景中非常有用。
你提出了一个很好的问题。Python 和 JavaScript 在处理异步操作 的方式上确实有一些区别。
在 Python 中,开发者通常可以使用 Pandas 这样的库来读取和处理 CSV 数据,而无需使用异步编程模式。这是因为 Python 解释器本身 具有一种称为 "GIL"(Global Interpreter Lock) 的机制,它可以确 保单个 Python 进程一次只执行一个 Python 字节码指令。
这意味着,即使在 Python 中执行 I/O 密集型操作(如读取 CSV 文 件),它也不会阻塞整个程序的执行,因为 GIL 会在 I/O 操作阻塞时 自动切换到其他可执行的 Python 代码。这与 JavaScript 的单线程 事件循环模型不同。
因此,在 Python 中,开发者通常不需要显式地使用异步编程模式(如 async/await),因为 Python 的运行时环境已经能够处理 I/O 操作, 而不会阻塞整个程序。
但是,如果 Python 程序需要处理大量的并发任务,或者需要在不阻塞 主线程的情况下执行长时间运行的操作,则使用异步编程模式(如 asyncio 库)可能会更加合适和高效。
总的来说,Python 和 JavaScript 在处理异步操作的方式上确实存在 一些区别,这是由于两种语言的运行时环境和设计目标不同所致。
I/O 操作指的是输入/输出操作,也就是计算机与外部设备或资源进行 数据交换的过程。常见的 I/O 操作包括:
文件读写 - 从磁盘或其他存储媒体读取数据,或向其写入数据。
网络通信 - 通过网络连接与远程服务器或其他设备进行数据传 输。
数据库操作 - 从数据库查询、插入、更新或删除数据。
设备控制 - 与键盘、鼠标、显示器等硬件设备进行交互。
这些 I/O 操作通常涉及磁盘、网络、数据库等外部资源,它们的响应 时间往往比内存中的计算操作要长得多。
在并发编程中,I/O 操作容易成为性能瓶颈,因为它们可能会阻塞程序 的其他部分,直到 I/O 操作完成。这就是为什么异步编程模式(如 JavaScript 中的 async/await 或 Python 中的 asyncio)非常有 用 - 它们允许程序在等待 I/O 操作完成时继续执行其他任务,从而 提高整体性能。
总之,I/O 操作指的是与外部设备或资源进行数据交换的过程,这些操 作通常比内存中的计算慢得多,因此需要特殊的编程模式来管理它 们。
并发式编程是指程序能够在同一时间处理多个任务的编程方法。它的 主要目标是提高程序的性能和响应速度。并发编程包括多线程、多进 程、异步编程和并行计算等不同的模式。下面是每种模式的简单介绍 和伪代码示例:
多线程是指在一个进程内创建多个线程,每个线程可以独立执行。它 们共享同一个进程的资源,因此可以更高效地进行任务切换,但也需 要注意线程安全问题。
伪代码示例:
import threading
def task1():
for i in range(5):
print("Task 1 - Step", i)
def task2():
for i in range(5):
print("Task 2 - Step", i)
# 创建线程
thread1 = threading.Thread(target=task1)
thread2 = threading.Thread(target=task2)
# 启动线程
thread1.start()
thread2.start()
# 等待线程完成
thread1.join()
thread2.join()
多进程是指同时运行多个独立的进程,每个进程有自己独立的内存空 间。多进程可以有效利用多核CPU,但进程间通信相对复杂。
伪代码示例:
import multiprocessing
def task1():
for i in range(5):
print("Task 1 - Step", i)
def task2():
for i in range(5):
print("Task 2 - Step", i)
# 创建进程
process1 = multiprocessing.Process(target=task1)
process2 = multiprocessing.Process(target=task2)
# 启动进程
process1.start()
process2.start()
# 等待进程完成
process1.join()
process2.join()
异步编程是指使用非阻塞的方式执行任务,常用于I/O密集型操作。
它使用事件循环来调度任务,通常与回调函数、async/await
等语
法结合使用。
伪代码示例:
import asyncio
async def task1():
for i in range(5):
print("Task 1 - Step", i)
await asyncio.sleep(1)
async def task2():
for i in range(5):
print("Task 2 - Step", i)
await asyncio.sleep(1)
async def main():
await asyncio.gather(task1(), task2())
# 运行异步任务
asyncio.run(main())
并行计算是指同时使用多个计算资源执行计算任务,通常用于计算密 集型操作。并行计算可以通过多线程、多进程或GPU加速实现。
伪代码示例(使用多进程池):
from multiprocessing import Pool
def compute_square(x):
return x * x
if __name__ == "__main__":
with Pool(4) as p:
results = p.map(compute_square, [1, 2, 3, 4, 5])
print(results)
总结:
选择合适的并发模式取决于具体的应用场景和任务需求。
不,.attr()
方法并不仅仅存在于 D3.js 中。它是一个更广泛使用
的方法,在以下几种情况下也可以使用:
JavaScript/jQuery: 在使用原生 JavaScript 或 jQuery 操
作 DOM 元素时,可以使用 .attr()
方法来设置元素的属性。例
如:
// 使用原生 JavaScript
document
.getElementById('myElement')
.setAttribute('width', '100');
// 使用 jQuery
$('#myElement').attr('width', '100');
D3.js: 正如您之前看到的,D3.js 库中也提供了 .attr()
方法来设置 SVG 元素的属性。
Vue.js: 在 Vue.js 中,可以使用 v-bind:
指令来绑定元
素的属性,它也是一种设置属性的方式。
React: 在 React 中,可以使用 props
来设置元素的属
性。
总之,.attr()
方法是一种广泛使用的设置元素属性的通用方法,不
仅存在于 D3.js 中,在许多其他 JavaScript 库和框架中也可以找
到。它为开发者提供了一种简单直观的方式来修改 DOM 元素的属
性。
three way to add: inline; internal; external