JS事件监听器(性能)

时间:2018-10-18 12:29:08

标签: javascript

我有一个具有10000个单元格(100行和100列)的简单表,每个单元都有click事件侦听器。我没有发现任何视觉性能问题。您能否详细解释一下我,为什么对性能如此不利?

P.S。我知道事件冒泡,最好在.get()上添加一个事件侦听器:)

<table>
const clickHandler = (event) => {
	console.log(event);
};

const getTable = (rowsNum, columnsNum) => {
	let row = '';
	let rows = '';

	for(let i = 0; i < columnsNum; ++i) {
		row += '<td onclick="clickHandler(event)"></td>';
	}

	for(let i = 0; i < rowsNum; ++i) {
		rows += `<tr>${row}</tr>`;
	}

	return `<table>${rows}</table>`
};

const innerTable = () => {
	document.querySelector('.table').innerHTML = getTable(100, 100);
};

innerTable();
table, td {
	border: 1px solid black;
}

td {
	width: 5px;
	height: 5px;
}

2 个答案:

答案 0 :(得分:1)

  

...为什么对性能如此不利?

执行此操作时:

<td onclick="clickHandler(event)"></td>

您要让浏览器为每个td 生成一个函数,因为它必须为该字符串属性中的代码生成包装函数。那是浪费时间和记忆。

相反,如果您重用处理程序:

const table = document.querySelector('.table');
table.innerHTML = getTable(100, 100);
table.querySelectorAll("td").forEach(td => {
  td.addEventListener("click", clickHandler);
});

显着地 更快:

const clickHandler = (event) => {
	console.log(event.type);
};

const getTable = (rowsNum, columnsNum) => {
	let row = '';
	let rows = '';

	for(let i = 0; i < columnsNum; ++i) {
		row += '<td></td>';
	}

	for(let i = 0; i < rowsNum; ++i) {
		rows += `<tr>${row}</tr>`;
	}

	return `<table>${rows}</table>`
};

const innerTable = () => {
  const table = document.querySelector('.table');
  table.innerHTML = getTable(100, 100);
  table.querySelectorAll("td").forEach(td => {
    td.addEventListener("click", clickHandler);
  });
};

innerTable();
table, td {
	border: 1px solid black;
}

td {
	width: 5px;
	height: 5px;
}
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Title</title>
	<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
	<div class="table">

	</div>

	<script src="script.js"></script>
</body>
</html>

如果进一步讲解并使用事件委托,甚至不需要循环调用addEventListener(因此设置起来会更快一些)添加和删​​除表格单元格,它们将被自动处理:

const table = document.querySelector('.table');
table.innerHTML = getTable(100, 100);
table.addEventListener("click", clickHandler);

const clickHandler = (event) => {
    const td = event.target.closest("td");
    if (!td) {
      return;
    }
    console.log(event.type);
};

const clickHandler = (event) => {
    const td = event.target.closest("td");
    if (!td) {
      return;
    }
	console.log(event.type);
};

const getTable = (rowsNum, columnsNum) => {
	let row = '';
	let rows = '';

	for(let i = 0; i < columnsNum; ++i) {
		row += '<td></td>';
	}

	for(let i = 0; i < rowsNum; ++i) {
		rows += `<tr>${row}</tr>`;
	}

	return `<table>${rows}</table>`
};

const innerTable = () => {
  const table = document.querySelector('.table');
  table.innerHTML = getTable(100, 100);
  table.addEventListener("click", clickHandler);
};

innerTable();
table, td {
	border: 1px solid black;
}

td {
	width: 5px;
	height: 5px;
}
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Title</title>
	<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
	<div class="table">

	</div>

	<script src="script.js"></script>
</body>
</html>

答案 1 :(得分:1)

一个事件处理程序将减少DOM和您自己管理的事件,这将使您更轻松,浏览器的性能也会更高。

事件委托是该模式的正确命名。它指的是使用冒泡处理DOM中更高级别的事件的过程。使用一个事件侦听器并在实际希望触发时过滤掉会更容易管理。

如果忘记删除事件侦听器,则可能会导致内存泄漏。

David Walsh提供了有关如何利用事件委托的不错的文章。 https://davidwalsh.name/event-delegate