日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

JS的异步讲解

發布時間:2024/4/13 javascript 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JS的异步讲解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

JS的異步由來已久,各種異步概念也早早堆在開發者面前。可現實代碼中,仍然充斥了各種因異步順序處理不當的bug,或因不好好思考,或因不了解真相。今天,就特來再次好好探索一番JS的異步世界。

?

01 異步的由來--單線程

上世紀末,互聯網仍處于極慢速時代,穿梭于客戶端與服務端的請求,對于時間的耗費是如此的奢侈。而即將面世的LiveScript,便被網景公司考慮同時在瀏覽器和服務端使用,在瀏覽器端對表單進行校驗,從而提高表單提交效率。為了將這一腳本語言推向市場,網景與sun聯合開發,最終以Java冠名為JavaScript。

剛面世的JavaScript,是為網頁設計人員準備的,不需要太復雜的語言設計,能簡單上手,自然就是最好的。

于是,單線程,弱類型,一開始就成為了JavaScript的基因。而其中的單線程,便是最戲劇性的存在,Ryan Dahl因為JavaScript是單線程語言,從而選擇了js開發了輕量級服務器(nodejs),使得js從瀏覽器端延伸到服務器。隨著JS開發隊伍和程序復雜度的同步發展,異步處理成為了JS程序的重中之重。

?

02 JS是一個充滿異步的世界

先來導入幾個異步的常見場景

dom用戶輸入響應
ducument.addEventListener('click', function(){})

Ajax
$.ajax(<url>, function() {})

定時/延時
setTimeout(function() {}, 1000) setInterval(function() {}, 1000)

文件讀取
var reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function() {}

以上的場景基本有個共同特性,耗時!

舉個栗子,我們去銀行取錢,當人很多時,如果還是排隊模式,會耗費很多時間(同步模式)。于是設立了取號機,取了號,不用排隊,在一旁坐著,安心打開電腦寫個文檔,等叫號后再去辦業務(異步模式)。

同理,由于單線程的特性,當JS應用越來越復雜,耗時的程序如果以同步來進行,就會阻塞js的單線程,如大水沖過狹窄的河道,勢必決堤。那JS是怎么開拓導流渠道的呢?其實在js的單線程(主線程)背后,規律的運行了很多線程:

  • dom事件處理線程
  • http請求線程
  • 定時器線程
  • ...
  • 這些線程就充當了JS大江的小河道,當短時有大流量時,接納吸收,將過濾處理后的正常水流,再匯入JS主干道。

    與其說JS是單線程,不如說JS是有著自動化多線程處理的主線程。無需手動編碼介入新開線程,切換線程,消息同步等冗繁的處理。專用線程會接管相關任務,并將處理結果送回主線程進行順序處理。

    說到這里稍微提一下web worker,雖然是自定義的多線程,最終還是子線程地位,仍舊將處理完成的結果以回調函數方式匯入到主線程進行異步處理。

    ?

    03 異步處理一般流程

    先看以下代碼,異步模式開始了

    var img = new Image() var imgLoadCallback = function() {} img.src = 'http://????' img.onload = callback

    ?

    “http君,麻煩幫取一個圖片數據,好了后交給imgLoadCallback君。” — js主線程老大
    “任務收到,您先忙,圖片請求交給我了,好了之后我叫imgLoadCallback君到休息室排隊,您空了通知下 Event Loop巡檢官。” — http請求線程

    img.src = 'http://????' img.onload = imgLoadCallback

    ?

    “圖片已取到,imgLoadCallback君去休息室排隊等候吧!” — http請求線程

    imgLoadCallback入棧JS任務隊列

    ?

    “剛好忙完手上的事情了,Event Loop君,幫看下休息室有沒有人排隊” — JS主線程老大
    “老大,已把等候者imgLoadCallback叫過來處理任務” — Event Loop巡檢官

    執行imgLoadCallback

    ?

    “事情都交給合適的人去辦了,突然就清閑下來了,老大就是要這樣當啊,嘿嘿嘿… Event Loop君,定時看下休息室有沒有人排隊吧… ” — JS主線程老大

    JS主線程通過Event Loop讀取任務隊列

    ?

    講完故事,再來看這張異步示意圖,是否能理解了?

    ?

    image

    ?

    04 回調處理工具的進化

    從前面的篇章已經能看出來了,異步處理的結果是通過回調放置到任務隊列轉接到主線程中的。

    北京猿人刀跟火種,這么寫異步回調,看上去也能令人接受。

    $.ajax(url: '自家香蕉樹林',data: {picker: '猴子A'},success: function(data) {$.ajax(url: '隔壁老孫家桃林',data: {exchanges: data.香蕉,buyer: '猴子A'},success: function(data) {console.log('向本猴王進貢', data.桃子)})} )

    ?

    進化成人類后交易過程變的復雜了,于是就變成回調地獄,傳說中的callback hell

    $.ajax(url: '自家香蕉樹林',data: {picker: '老王'},success: function(data) {$.ajax(url: '集市販賣',data: {goods: data.香蕉,seller: '老王'},success: function(data) {$.ajax(url: '隔壁老李桃子鋪',data: {exchanges: data.錢,buyer: '老王'},success: function(data) {console.log('向本王進貢', data.桃子)})})} )

    ?

    于是發明了鐵器promise,解決回調地獄之痛

    $.ajax(url: '自家香蕉樹林',data: {picker: '老王'} ) .then(function(data) {return $.ajax(url: '集市販賣',data: {goods: data.香蕉,seller: '老王'}) }) .then(function(data) {return $.ajax(url: '隔壁老李桃子鋪',data: {exchanges: data.錢,buyer: '老王'}) }) .then(function(data) {console.log('向本王進貢', data.桃子) })

    ?

    關于promise的升級版async、await,本篇不多說了,理念上基本一致。

    繼續...

    這下一次命令,只會來供給本王一次桃子,每次都要發令,好麻煩,得下個令讓老王每天去賣香蕉買桃子,給我月供100個,于是就發生了以下的故事

    var contributeTime; setInterval(function(){$.ajax(url: '自家香蕉樹林',data: {picker: '老王'}).then(function(data) {return $.ajax(url: '集市販賣',data: {goods: data.香蕉,seller: '老王'})}).then(function(data) {return $.ajax(url: '隔壁老李桃子鋪',data: {exchanges: data.錢,buyer: '老王'})}).then(function(data) {var currentTime = new Date().getTime();if (!contributeTime || (currentTime - contributeTime > '月')) {console.log('向本王進貢', [data.桃子,…]); //length=100currentTime = contributeTime;}}) }, '天')

    ?

    這過程,好像也太不優雅了點。

    ReactX的JS版,RxJs來了,將異步看作為單點,將其擴展了時間線,作為流來處理。所以對于一次又一次的進貢,都可進行時序管理,于是整個過程變成這樣:

    import { ajax } from 'rxjs/ajax'; //此處特別寫引入,目的為不與jquery.ajax混淆 import { interval } from 'rxjs'; const ob = interval('天'); const peachPay = ob.pipe(switchMap(x => ajax.post('自家香蕉樹林', {picker: '老王'}))).pipe(switchMap(data => ajax.post('集市販賣', {seller: '老王', goods: data.香蕉}))).pipe(switchMap(data => ajax.post('隔壁老李桃子鋪', {buyer: '老王', exchanges: data.錢}))).pipe(throttle(data => interval('月'))).subscribe(data => console.log(`每月收到月供:${data.桃子.length}個${data.桃子}`));

    整個過程順著管道不斷變換處理,就是一條全自動流水線!然鵝,然鵝,并一定每月就能供出100個桃子啊,萬一遇到農災,或者經濟蕭條…

    以上例子僅提供思路,且讀且珍重!

    ?

    05 比工具更重要的,是理解

    前端開發中,諸多剪不斷理還亂的偶現bug來源于異步處理的順序混亂。即便是異步處理工具越來越先進,由于代碼層面的順序和真實執行順序的不一致,也還是容易一不小心犯錯誤。

    異步處理工具不是萬能的,還是需不斷將異步原理內化入思維模式中,種碼的時候,就需清晰的知道該段代碼會什么時候結出果實。

    ?

    ?

    總結

    以上是生活随笔為你收集整理的JS的异步讲解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。