概念 什么是JS異步
異步加載也叫非阻塞模式加載,瀏覽器在下載js的同時,還會執行后續的頁面處理.
何時需要異步
1 需要等待的情況
2 在等待過程中不能像alert一樣阻塞程序運行
3 等待的情況需要異步
使用場景:
1 定時任務setTimeout, setInterval
console.log(100); setTimeout(function(){ console.log(200); },1000); //異步執行,非阻塞並不妨礙后續代碼執行 console.log(300); //執行順序為100 300 200
2 網絡請求 ajax 動態<img> 加載
console.log("start"); var img=document.createElement("img"); img.onload=function(){ console.log("loaded"); } img.src="https://ps.ssl.qhimg.com/sdmt/75_135_100/t01525fd8d9773b149f.jpg"; document.body.append(img); console.log("end"); //執行順序是 start end loaded 圖片的加載時異步的
3 事件綁定
console.log("start"); document.getElementById("btn").addEventListener("click",function(){ console.log("clicked"); }); console.log("end"); //執行順序是start ,end 如果點擊才執行clicked 如果不點永遠不執行 也是異步的
典型的同步加載的例子:
console.log(100); alert(200); console.log(300); //同步打印100,彈出200,打印300,取決於按下‘確定’框的時間,不按就一直卡頓在那
同步或非同步,表明着是否需要將整個流程按順序地完成
阻塞或非阻塞,意味着你調用的函數會不會立刻告訴你結果
二、在js中的阻塞與同異步
你有一個函數和一段程序。
2.1 js中的同步阻塞
// 這是一個阻塞式函數, 將一個文件復制到另一個文件上 function copyBigFile(afile, bfile){ var result = copyFileSync(afile,bfile); return result; }
調用這個”copyBigFile()”函數,將一個大文件復制到另一個文件上,將耗時1小時。意味着這個函數的將在一個小時之后返回。
//這是一段程序 console.log("start copying ... "); var a = copyBigFile('A.txt', 'B.txt'); //這行程序將耗時1小時 console.log("Finished"); // 這行程序將在一小時后執行 console.log("處理一下別的事情"); // 這行程序將在一小時后執行 console.log("Hello World, 整個程序已加載完畢,請享用"); // 這行程序將在一小時后執行
以上的程序就是一個同步阻塞的例子,因為copyFileSync函數返回值的過程需要漫長的時間,所以線程也無法繼續執行下去,只能等待。
2.2 js中的同步非阻塞
// 這是一個非阻塞式函數 // 如果復制已完成,則返回 true, 如果未完成則返回 false function copyBigFile(afile,bfile){ var copying = copyFileAsync(afile, bfile); var isFinished = !copying; return !isFinished; }
調用這個函數將立刻返回結果,然后你的程序就可以寫成
console.log("start copying ... "); while( a = copyBigFile('A.txt', 'B.txt')){ console.log("在這之間還可以處理別的事情"); } ; console.log("Finished"); // 這行程序將在一小時后執行 console.log("Hello World, 整個程序已加載完畢,請享用"); // 這行程序將在一小時后執行
一個非阻塞式的函數,給你的編程帶來了更多的便利,你可以在長IO操作的同時,寫點其他的程序,提高效率。執行結果如下
start copying ... 在這之間還可以處理別的事情 在這之間還可以處理別的事情 在這之間還可以處理別的事情 ... Finished Hello World, 整個程序已加載完畢,請享用
2.3 js中的異步非阻塞
我們看到,一個非阻塞式的函數能給我們編程帶來許多靈活性,我們喜歡非阻塞式的函數。
但是,又可以看到同步的程序需要在一個循環中輪詢結果,循環里面的程序會被執行好多遍,所以並不好控制來寫一些正常的程序,很難再利用起來。
所以我們需要一種更為合理的方式對非阻塞式的函數進行利用。
也就是我不會主動地去詢問結果,而是當你有了結果的時候再來通知我。
// 這是一個非阻塞式函數
// 如果復制已完成,則返回 true, 如果未完成則返回 false
//非阻塞式的有異步通知能力的函數 //以下不需要看懂,只用知道這個函數會在完成copy操作之后,執行success function copyBigFile(afile,bfile, callback){ var copying = copyFileAsync(afile, bfile, function(){ callback();}); var isFinished = !copying; return !isFinished; }
這個函數不同於上一個同步非阻塞函數的地方在於,它具有通知功能,也就是說,它能夠在完成操作之后主動地通知程序,“我完成了”。於是有程序如下,
console.log("start copying ... "); copyBigFile("A.txt","B.txt", function(){ console.log("Finished"); //一個小時后被執行 console.log("Hello World, 整個程序已加載完畢,請享用"); //一個小時后被執行 }) console.log("干別的事情"); console.log("做一些別的處理");
程序在調用copyBigFile函數之后,可以立即獲得返回值,線程沒有被阻塞住,於是還可以去干些別的事情,然后當copyBigFile完成之后,會執行指定的函數。所以程序的輸出應為,
start copying ...
干別的事情
做一些別的處理
Finished
Hello World, 整個程序已加載完畢,請享用
在這種情況下,程序更容易控制,流程更為清晰。一些“別的事情”可以在函數還未通知之前進行處理,充分地提高了線程的利用效率。
