手把手帶你去理解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);
非同步程式設計的三種方式
callbackfunction 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);
},
});
},
});
}
登入後複製
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
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 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 | 問題? ?如果多個非同步程式碼同時存在,那麼執行順序應該是怎麼樣的?那個先執行、那個後執行了? |
---|---|
非同步程式碼的劃分,非同步程式碼分宏任務和微任務。
| |
#微任務(急) |
事件循环(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)是非同步程式設計中的
