day14_同步和異步
-
同步
首先福铅,我們要知道萝毛,JavaScript的本質(zhì)是一門瀏覽器腳本語言,在執(zhí)行的時候是一行一行的執(zhí)行滑黔,只有前面的代碼執(zhí)行完了才會執(zhí)行后面的代碼笆包。
JS是單線程語言指的就是這個意思环揽。
-
異步
一個任務(wù)是否是異步,要看程序員在編寫代碼的時候是否將這個任務(wù)設(shè)置為異步庵佣,而不是說時間長的任務(wù)就一定是異步的歉胶,只是通常來講為了流暢性,編程者會將執(zhí)行時間長的任務(wù)主觀的設(shè)置為異步巴粪。
那么這里就涉及到一個問題了通今,怎么將一個任務(wù)設(shè)置為異步?
JS中最基礎(chǔ)的有兩種方式——setTimeout函數(shù)和setInterval函數(shù)肛根。
- 循環(huán)打印“紅”衡创、“黃”、“綠” 燈
// 紅燈 function first(red, yellow, green) { setTimeout(function () { console.log("紅"); // yellow(green,red,yellow) second(yellow, green, red); }, 1000) } // 黃燈 // yellow(green,red,yellow) function second(yellow, green, red) { setTimeout(function () { console.log("黃"); // green(red,yellow,green) third(green, red, yellow); }, 1000) } // 綠燈 // green(red,yellow,green) function third(green, red, yellow) { setTimeout(function () { console.log("綠"); first(red, yellow, green); }, 1000) } first(second, third, first);
- 異步加載圖片
class Box { constructor(time) { setTimeout(() => { var img = new Image(); img.src = "./img/36-.jpg"; img.addEventListener("load", e => { this.loadHandler(e); }) }, time) } loadHandler(e) { var evt = new Event("loadFinish"); evt.img = e.currentTarget; document.dispatchEvent(evt); } } class Ball { constructor(time) { setTimeout(() => { var img = new Image(); img.src = "./img/37.jpg"; img.addEventListener("load", e => { this.loadHandler(e); }) }, time) } loadHandler(e) { var evt = new Event("loadFinish"); evt.img = e.currentTarget; document.dispatchEvent(evt); } } class Main { arr = []; constructor() { document.addEventListener('loadFinish', e => { this.loadHandler(e); }) } loadHandler(e) { this.arr.push(e.img); if (this.arr.length === 2) { console.log(this.arr.reduce((value, item) => value + item.width, 0)); } } } var main = new Main(); var box = new Box(2000); var ball = new Ball(1000); //頁面加載3秒后晶通,顯示兩張圖片寬度之和
-
HTML頁面加載順序
- DOM的創(chuàng)建 script的加載,css的加載
- 形成CSS樣式樹,與DOM樣式樹合并,形成渲染樹
- 異步加載所有圖片
- 全部加載完成
-
async
async 相對于頁面的其余部分異步地執(zhí)行(當(dāng)頁面繼續(xù)進(jìn)行解析時,腳本將被執(zhí)行)
如果既不使用 async 也不使用 defer:在瀏覽器繼續(xù)解析頁面之前哟玷,立即讀取并執(zhí)行腳本狮辽。
注意:async 屬性僅適用于外部腳本(只有在使用 src 屬性時)。
-
defer
如果腳本不會改變文檔的內(nèi)容巢寡,可將 defer 屬性加入到
script
標(biāo)簽中喉脖,以便加快處理文檔的速度。因為瀏覽器知道它將能夠安全地讀取文檔的剩余部分而不用執(zhí)行腳本抑月,它將推遲對腳本的解釋树叽,直到文檔已經(jīng)顯示給用戶為止。
注意: 只有IE支持
2.異步轉(zhuǎn)同步
-
async
異步阻塞變?yōu)橥角酰会槍romise题诵,對于setTimeout不起作用
async function fn(){
//async函數(shù)中return就會執(zhí)行這個函數(shù)執(zhí)行返回的promise的resolve方法
//因此可以在then中獲取
return 1;
}
//async函數(shù)執(zhí)行后就是返回一個Promise
var a=fn();
a.then(function(value){
console.log(value);
})
-
當(dāng)async修飾的函數(shù)的函數(shù)體為空時
- 獲取fn的值是Promise
- 狀態(tài)是resolved
async function fn(){
}
console.log(fn());
//Promise {<resolved>: undefined}
- async與await
async function fn(){
console.log("a");
// 異步阻塞,變成了同步
await loadImage("./img/2-.jpg").then(function(img){
console.log(img);
});
console.log("b");
}
function loadImage(src){
return new Promise(function(resolve,reject){
let img=new Image();
img.src=src;
img.onload=function(){
resolve(img);
}
})
}
fn();
//a
//打印img
//b
- await阻斷Promise的異步,等待其中的resolve
async function fn(){
console.log("aaa");
// 只有Promise的狀態(tài)發(fā)生改變時才會繼續(xù)向下執(zhí)行await后面的內(nèi)容
await new Promise(function(resolve,reject){
}).then(function(){
console.log("bbb");
}).catch(function(){
console.log("ddd");
})
console.log("ccc");
}
fn();
//aaa
- 用async和await處理promise.all()
function loadImage(src){
return new Promise(function(resolve,reject){
let img = new Image();
img.src = src;
img.onload = function(){
resolve(img);
}
})
}
class Promise1{
static async all(arr){
let list = [];
for(let i = 0; i < arr.length; i++){
//將promise異步轉(zhuǎn)換為同步等待
await arr[i].then(function(img){
list.push(img);
})
}
return list;
}
}
var arr = [];
for(let i = 2; i < 80; i++){
arr.push(loadImage("./img/" + i + "-.jpg"));
}
Promise1.all(arr).then(function(list){
console.log(list);
})
- 實現(xiàn)循環(huán)打印 “紅黃綠" 燈
function showLight(color,time){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(color);
},time)
});
}
async function show(){
await showLight("紅色",2000).then(color=>console.log(color));
await showLight("黃色",2000).then(color=>console.log(color));
await showLight("綠色",2000).then(color=>{
console.log(color);
show();
});
}
show()