手把手带你弄懂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 代码的线程只有一个,不妨叫它主线程。
所谓单线程,就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成再执行后面一个任务。
先看看一下浏览器内核的线程图:
其中,渲染线程和 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);
回调函数的缺点也很明显,容易产生回调地狱:
异步编程的三种方式
- 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)
执行顺序:
执行整体代码
<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中文网其他相关文章!

热AI工具

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

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

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

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

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

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

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

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

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

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

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

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

异步编程,英文AsynchronousProgramming,是指程序中的某些任务可以并发地执行,而无需等待其他任务完成,从而提高程序的整体运行效率。在python中,asyncio模块是实现异步编程的主要工具,它提供了协程、事件循环和其他异步编程所需的组件。协程:协程(Coroutine)是一种特殊的函数,它可以被暂停然后恢复执行,就像线程一样,但协程比线程更轻量级,内存消耗更低。协程由async关键字声明,并在await关键字处暂停执行。事件循环:事件循环(EventLoop)是异步编程中的
