博客列表 >js 运行机制

js 运行机制

至诚网络的博客
至诚网络的博客原创
2021年10月06日 23:27:48732浏览

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>
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议