Blogger Information
Blog 18
fans 1
comment 1
visits 11416
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
js 运行机制
至诚网络的博客
Original
745 people have browsed it

js 运行机制

1单线程

  • 单线程在程序执行时,所走的程序会按照连续顺序排下来,前面的必须处理好,后面的才会执行。
  • 同一时刻,只能执行一个代码 ,一个任务接一个任务的执行, 代码的”书写顺序”与”执行顺序” 基本是一致的
  • js确实只有一个线程(由JS引擎维护),这个线程用来负责解释和执行JavaScript代码,我们可以称其为主线程。
  1. <script>
  2. // 正常都在主线程里执行 代码的"书写顺序"与"执行顺序" 一致
  3. console.log(1);
  4. console.log(2);
  5. console.log(3);
  6. console.log("--------");
  7. // 现在给console.log(2) 加一个定时任务
  8. console.log(1);
  9. // 定时任务: setTimeout(函数,等待时间)
  10. // 要等待三秒后才执行,这三秒理论上说,是什么也做不了,代码到这里就"阻塞"
  11. setTimeout(() => console.log(2), 3000);
  12. // 这个时候 js引擎将 setTimeout(() => console.log(2), 3000); 脱离"主线程",放到了"任务队列"的地方
  13. console.log(3);
  14. // 当主线程上已没有任务的时候,由"事件循环"将这个任务重新放回到主线程中执行
  15. // 定时任务就是一个异步任务,只要是异步任务,就不在主线程执行,到任务队列中,等"事件循环"来找它
  16. // 执行机制
  17. // 1. 同步任务: 主线程
  18. // 2. 异步任务: 任务队列, 由"事件循环"来调度
  19. // 哪些是异步任务?
  20. // 1. 定时任务, 2. 事件, 3, IO操作(input,output), 4. http请求
  21. // 怎么实现异步? 回调函数
  22. </script>

事件循环

  • 当主线程上同步任务全部执行完成后 ,由”事件循环”将在任务队列中的 异步任务 放回到主线程中去执行
  • “事件循环”就是来调度 异步任务 的
  1. <form action="">
  2. <input type="text" onkeydown="console.log(this.value);" />
  3. <!-- 为什么慢半拍? -->
  4. <!-- 因为dom渲染是同步任务,keydown事件是异步任务,所以总是获取的上一个数据 -->
  5. <!-- 解决方案很粗暴,就是异步事件等等,等同步的dom渲染完了再执行 -->
  6. <input type="text" onkeydown="setTimeout(()=>console.log(this.value),0);" />
  7. <!-- <input type="text" oninput="console.log(this.value);" /> -->
  8. </form>

事件添加

  1. <body style="display: grid; gap: 0.5em">
  2. <!-- 1. 事件属性 -->
  3. <button onclick="alert('hello')">事件属性</button>
  4. <!-- 2. 元素对象 -->
  5. <button>元素对象</button>
  6. <script>
  7. const btn2 = document.querySelector("button:nth-of-type(2)");
  8. btn2.onclick = () => console.log(111);
  9. btn2.onclick = _ => console.log(222);
  10. btn2.onclick = $ => console.log(333); // 会进行覆盖 只会执行这一个
  11. // 移除
  12. // btn2.onclick = null;
  13. </script>
  14. <!-- 3. 事件监听器 -->
  15. <button>事件监听器</button>
  16. <script>
  17. const btn3 = document.querySelector("button:nth-of-type(3)");
  18. // btn3.addEventListener(事件类型, 事件回调,是否冒泡false/捕获true)
  19. let i = 0;
  20. btn3.addEventListener("click", () => { i += 0.5;console.log(i)});
  21. btn3.addEventListener("click", () => { console.log(i)});
  22. btn3.addEventListener("click", () => { console.log(i)}); // 会全部执行
  23. // 删除 比较麻烦 只能用 removeEventListener 进行移除 并且添加的匿名函数无法移除
  24. let show = () => console.log(444);
  25. btn3.addEventListener("click", show);
  26. // 删除
  27. btn3.removeEventListener("click", show);
  28. </script>
  29. <!-- 4. 事件派发 -->
  30. <button>事件派发</button>
  31. <script>
  32. const btn4 = document.querySelector("button:nth-of-type(4)");
  33. // let i = 0;
  34. btn4.addEventListener("click", () => {
  35. i += 0.5;
  36. console.log("恭喜你, 又赚了: " + i + " 元");
  37. });
  38. // 4.1创建一个自定义事件
  39. const myclick = new Event("click");
  40. // 4.2派发 触发自定义事件
  41. // btn4.dispatchEvent(myclick);
  42. // btn4.dispatchEvent(myclick);
  43. // setTimeout: 定时器,用于执行一次性的定时任务
  44. // setInterval: 定时器, 用于执行间歇性的定时任务
  45. // setInterval(() => btn4.dispatchEvent(myclick), 3000);
  46. </script>

事件冒泡

  • 在一个对象上触发某类事件,如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序, 那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活)

  • 事件冒泡允许多个操作被集中处理, 把事件处理器添加到一个父级元素上,避免把事件处理器添加到多个子级元素上,

  • 事件冒泡机制有时候是不需要的,需要阻止掉,通过 event.stopPropagation() 来阻止。

  • 事件委托:就是利用冒泡的原理,把事件加到父级上,通过判断事件来源的子集,执行相应的操作,事件委托首先可以极大减少事件绑定次数,提高性能;其次可以让新加入的子元素也可以拥有相同的操作。 事件委托的关系是将子元素的事件委托到父元素上。

  1. <!-- event: 事件对象 -->
  2. <button onclick="show(event)">click</button>
  3. <ul>
  4. <li>item1</li>
  5. <li>item2</li>
  6. <li>item3</li>
  7. <li>item4</li>
  8. <li>item5</li>
  9. </ul>
  10. <script>
  11. function show(ev) {
  12. // ev: 事件对象
  13. // console.log(ev);
  14. // ev中有二个特别重要的属性
  15. // 1. 事件绑定者(主体) currentTarget
  16. // console.log(ev.currentTarget);
  17. // 2.事件触发者(目标) target
  18. // console.log(ev.target);
  19. // console.log(ev.target === ev.currentTarget); //返回 true
  20. }
  21. const lis = document.querySelectorAll("li");
  22. // 循环给每一个li添加点击事件
  23. // lis[0].onclick = function(){alert(111)}
  24. lis.forEach(function (li) {
  25. li.onclick = function (ev) {
  26. console.log(ev.target);
  27. };
  28. });
  29. // lis.forEach(li => (li.onclick = ev => console.log(ev.currentTarget)));
  30. // onclick这种通过 事件属性 的添加的事件,是冒泡事件
  31. // 冒泡: 子元素的同名事件,会沿着dom树向上逐级触发上级元素的同名事件
  32. // 获取 html === document.documentElement
  33. // 事件委托:
  34. document.querySelector("ul").onclick = (ev) => {
  35. // 1.事件绑定者
  36. // console.log(ev.currentTarget);
  37. // 2. 事件触发者
  38. // console.log(ev.target);
  39. // console.log(ev.target.textContent);
  40. // console.log(ev.target === ev.currentTarget); //返回false
  41. };
  42. </script>

表单事件

  1. <!-- 阻止默认行为 :event.preventDefault() 阻止冒泡事件 : event.stopPropagation()
  2. 上述两个操作可以合并为:return false; -->
  3. <form action="" method="post" id="login" onsubmit="return false">
  4. <label class="title">用户登录</label>
  5. <label for="email">邮箱:</label>
  6. <input type="email" id="email" name="email" value="" autofocus />
  7. <label for="password">密码:</label>
  8. <input type="password" id="password" name="password" />
  9. <button name="submit">登录</button>
  10. </form>
  11. <script>
  12. // form
  13. const login = document.forms.login;
  14. // submit: 提交事件 这里直接提交会报错 表单有一个默认的提交行为 推荐用 禁用默认行为 onsubmit="return false"
  15. // login.onsubmit = () => console.log("提交了");
  16. // 这个也可以 禁用表单的提交行为
  17. // 阻止默认行为 event.preventDefault()
  18. // login.onsubmit = ev => ev.preventDefault();
  19. // 为什么要禁用原生的提交行为?因为我想在提交进行验证和处理
  20. login.submit.onclick = ev => {
  21. // 阻止冒泡事件 : event.stopPropagation()
  22. ev.stopPropagation();
  23. // 每个表单元素都有一个form属性,与所属的表单绑定
  24. console.log(ev.currentTarget.form);
  25. // 非空验证
  26. isEmpty(ev.currentTarget.form);
  27. };
  28. function isEmpty(form) {
  29. if (form.email.value.length === 0) {
  30. alert("邮箱不能为空");
  31. form.email.focus();
  32. return false;
  33. } else if (form.password.value.trim().length === 0) {
  34. alert("密码不能为空");
  35. form.email.focus();
  36. return false;
  37. } else {
  38. alert("验证通过");
  39. }
  40. }
  41. </script>
Correcting teacher:PHPzPHPz

Correction status:qualified

Teacher's comments:
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post