目录
目的
引子问题
产生异步的原因
异步编程
异步代码
回调函数
异步编程的三种方式
在线预览
问题??
宏任务和微任务
事件循环(Event loop)
总结
练习
首页 web前端 js教程 手把手带你弄懂JavaScript中的异步编程

手把手带你弄懂JavaScript中的异步编程

Jun 03, 2021 am 11:02 AM
javascript 异步编程

本篇文章带大家了解JavaScript中的异步编程。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

手把手带你弄懂JavaScript中的异步编程

异步,就是非同步....

这节内容可能会有点枯燥,但是却是 JavaScript 中非常重要的概念,非常有必要去学习。

目的

  • 提升开发效率,编写易维护的代码

引子问题

  • 请求时候为什么页面卡死??
$.ajax({
  url: "www.xx.com/api",
  async: false, // true
  success: function(result) {
    console.log(result);
  },
});
登录后复制
  • 为什么数据更新了,DOM 却没有更新??
// 异步批量更新DOM(vue-nextTick)
// <p id="app">{{num}}</p>
new Vue({
  el: "#app",
  data: {
    num: 0,
  },
  mounted() {
    let dom = document.getElementById("app");
    while (this.num !== 100) {
      this.num++;
    }
    console.log("Vue num=" + this.num, "DOM num=" + dom.innerHTML);
    // Vue num=100,DOM num=0
    // nextTick or setTimeout
  },
});
登录后复制

产生异步的原因

原因:单线程(一个时间点,只做一件事),浏览器的 JS 引擎是单线程导致的。

单线程是指在 JS 引擎中负责解释和执行 IavaScript 代码的线程只有一个,不妨叫它主线程。

所谓单线程,就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成再执行后面一个任务。

先看看一下浏览器内核的线程图:

1.jpg

其中,渲染线程和 JS 线程互斥

假设有两个函数,一个修改一个删除,同时操作一个 DOM 节点,假如有多个线程的话,两个线程一起执行,肯定就死锁了,就会有问题。

为什么 JS 要设计为单线程,因为浏览器的特殊环境。

单线程的优缺点:

这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段 Javascript 代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。

常见的堵塞(死循环):

while (true) {}
登录后复制

JS 在设计之初就以运行在浏览器中的脚本语言,所以也不想搞得这么复杂,就设计成了单线程,也就是,一个时间点,只能做一件事。

为了解决单线程堵塞这个缺点:产生了异步。

拿吃泡面举例:

  • 同步:买泡面=》烧水(盯着)=》煮面=》吃泡面
  • 异步:买泡面=》烧水(水开了热水壶响-回调)=》看电视=》煮面(面好了热水壶响-回调)=》看电视=》熟了叫我=》吃泡面

看电视就是异步操作,热水壶响,就是回调函数。

异步编程

JS 中大多的代码都是同步执行的,只有极个别的函数是异步执行的,异步执行的代码,则需要异步编程。

异步代码

setTimeout(() => {
  console.log("log2");
}, 0);
console.log("log1");
// ?? log1 log2
登录后复制

异步代码的特点:不是立即执行,而是需要等待,在未来的某一个时间点执行。

同步代码异步代码
<script>代码网络请求(Ajax)
I/O 操作定时器(setTimeout、setInterval)
渲染操作Promise(then)

async/await

回调函数

异步代码最常见的写法就是使用回调函数。

  • HTTP 网络请求(请求成功、识别后执行 xx 操作)
  • DOM 事件绑定机制(用户触发事件后执行 xx 操作)
  • 定时器(setTimeout、setInterval)(在达到设定时间后执行 xx 操作)
// 注意到click方法中是一个函数而不是一个变量
// 它就是回调函数
$("#btn_1").click(function() {
  alert("Btn 1 Clicked");
});
// 或者
function click() {
  // 它就是回调函数
  alert("Btn 1 Clicked");
}
$("#btn_1").click(click);
登录后复制

回调函数的缺点也很明显,容易产生回调地狱:

2.png

异步编程的三种方式

  • callback
function getOneNews() {
  $.ajax({
    url: topicsUrl,
    success: function(res) {
      let id = res.data[0].id;
      $.ajax({
        url: topicOneUrl + id,
        success: function(ress) {
          console.log(ress);
          render(ress.data);
        },
      });
    },
  });
}
登录后复制
  • promise
function getOneNews() {
  axios
    .get(topicsUrl)
    .then(function(response) {
      let id = response.data.data[0].id;
      return axios.get(topicOneUrl + id);
    })
    .then((res) => {
      render(res.data.data);
    })
    .catch(function(error) {
      console.log(error);
    });
}
登录后复制
  • async/await
async function getOneNews() {
  let listData = await axios.get(topicsUrl);
  let id = listData.data.data[0].id;
  let data = await axios.get(topicOneUrl + id);
  render(data.data.data);
}
登录后复制

在线预览

预览地址:http://jsrun.net/s43Kp/embedded/all/light

问题??

如果多个异步代码同时存在,那么执行顺序应该是怎样的?那个先执行、那个后执行了?

宏任务和微任务

异步代码的划分,异步代码分宏任务和微任务。

宏任务(不着急)微任务(着急)
<script>整体代码Promise
setTimeout/setInterval

事件循环(Event loop)

3.png

执行顺序:

  • 执行整体代码<script>(宏任务)

  • 执行所有微任务

  • 执行一个宏任务

  • 执行渲染线程

  • 2->3->2->3...依次循环(在 2、3 步中又创建了新的宏、微任务)

重复从宏任务和微任务队列里拿出任务去执行。

总结

因为浏览器设计的原因,JS 线程和渲染线程互斥,所以 JS 线程被设计成了单线程。

因为单线程执行一些操作(如网络请求)时有堵塞的问题,所有产生了异步。

因为有了异步,所以产生了异步编程,从而有了回调函数。

因为回调函数写多了会产生回调地狱,所有又有了解决回调地狱的 Promise 写法

自 ES7 标准后有了比 Promise 更加优雅的写法 ———— async/await 写法,也是异步编程的最终解决方法。

因为 JS 的代码分为同步和异步代码,同步代码的执行顺序不必多说,自上而下的执行。

但是如果有多个异步的代码,他的执行顺序又是怎么的呢??

为了解决多个异步代码的执行顺序问了,有了事件循环(EventLoop),将异步任务区分为宏任务、微任务,依据规则依次执行。

至此 完!

练习

console.log("script start");
setTimeout(function() {
  console.log("timeout1");
}, 10);
new Promise((resolve) => {
  console.log("promise1");
  resolve();
  setTimeout(() => console.log("timeout2"), 10);
}).then(function() {
  console.log("then1");
});
console.log("script end");
登录后复制

写出 log 的输出结果,并说出理由。

更多编程相关知识,请访问:编程视频!!

以上是手把手带你弄懂JavaScript中的异步编程的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何用 C++ 函数实现异步编程? 如何用 C++ 函数实现异步编程? Apr 27, 2024 pm 09:09 PM

摘要:C++中的异步编程允许多任务处理,无需等待耗时操作。使用函数指针创建指向函数的指针。回调函数在异步操作完成时被调用。boost::asio等库提供异步编程支持。实战案例演示了如何使用函数指针和boost::asio实现异步网络请求。

简易JavaScript教程:获取HTTP状态码的方法 简易JavaScript教程:获取HTTP状态码的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教程:如何获取HTTP状态码,需要具体代码示例前言:在Web开发中,经常会涉及到与服务器进行数据交互的场景。在与服务器进行通信时,我们经常需要获取返回的HTTP状态码来判断操作是否成功,根据不同的状态码来进行相应的处理。本篇文章将教你如何使用JavaScript获取HTTP状态码,并提供一些实用的代码示例。使用XMLHttpRequest

Java框架异步编程中的常见问题与解决方案 Java框架异步编程中的常见问题与解决方案 Jun 04, 2024 pm 05:09 PM

Java框架异步编程中常见的3个问题和解决方案:回调地狱:使用Promise或CompletableFuture以更直观的风格管理回调。资源竞争:使用同步原语(如锁)保护共享资源,并考虑使用线程安全集合(如ConcurrentHashMap)。未处理异常:明确处理任务中的异常,并使用异常处理框架(如CompletableFuture.exceptionally())处理异常。

golang框架如何处理并发和异步编程? golang框架如何处理并发和异步编程? Jun 02, 2024 pm 07:49 PM

Go框架利用Go的并发和异步特性提供高效处理并发和异步任务的机制:1.通过Goroutine实现并发,允许同时执行多个任务;2.通过通道实现异步编程,在不阻塞主线程的情况下执行任务;3.适用于实战场景,如并发处理HTTP请求、异步获取数据库数据等。

如何在JavaScript中获取HTTP状态码的简单方法 如何在JavaScript中获取HTTP状态码的简单方法 Jan 05, 2024 pm 01:37 PM

JavaScript中的HTTP状态码获取方法简介:在进行前端开发中,我们常常需要处理与后端接口的交互,而HTTP状态码就是其中非常重要的一部分。了解和获取HTTP状态码有助于我们更好地处理接口返回的数据。本文将介绍使用JavaScript获取HTTP状态码的方法,并提供具体代码示例。一、什么是HTTP状态码HTTP状态码是指当浏览器向服务器发起请求时,服务

Python异步编程: 实现高效并发的异步代码之道 Python异步编程: 实现高效并发的异步代码之道 Feb 26, 2024 am 10:00 AM

1.为什么要使用异步编程?传统编程使用阻塞式I/O,这意味着程序会等待某个操作完成,然后才能继续执行。这对于处理单个任务来说可能很有效,但对于处理大量任务时,可能会导致程序变慢。异步编程则打破了传统阻塞式I/O的限制,它使用非阻塞式I/O,这意味着程序可以将任务分发到不同的线程或事件循环中执行,而无需等待任务完成。这允许程序同时处理多个任务,提高程序的性能和效率。2.python异步编程的基础Python异步编程的基础是协程和事件循环。协程是允许函数在暂停和恢复之间切换的函数。事件循环则负责调度

PHP 异步编程的优势与劣势? PHP 异步编程的优势与劣势? May 06, 2024 pm 10:00 PM

异步编程在PHP中的优势包括更高的吞吐量、更低的延迟、更好的资源利用和可扩展性。其劣势包括复杂性、调试难度和有限的库支持。实战案例中,ReactPHP用于处理WebSocket连接,展示了异步编程的实际应用。

Golang异步编程的优势与挑战:你需要知道的一切! Golang异步编程的优势与挑战:你需要知道的一切! Apr 03, 2024 pm 03:06 PM

优势:性能提升:并行任务执行,充分利用多核处理器。可伸缩性:轻松扩展以处理更大的工作负载。响应性:主线程不阻塞,保持应用程序响应性。资源优化:避免锁定和同步结构的需求。挑战:代码复杂性:管理多个独立任务。调试困难:任务在不同的线程或协程中执行。错误处理:并发环境中的错误处理复杂,需要额外的措施。实战案例:并行下载文件,使用Goroutine同时下载多个文件,展示异步编程如何提高性能。

See all articles