同步和異步問題

一、什麼叫同步、異步:
1、同步:同步操作沒有結束之前,後面的代碼是無法執行的。
2、異步:異步操作沒有結束之前,後面的代碼是可以執行的。
二、哪些是異步問題:
1、計時函數:setTimeout()、setInterval()。
2、資源加載(I/O操作):在JavaScript腳本代碼中動態加載資源。
3、XHR請求:利用Ajax技術向服務器發出請求。
三、異步問題的實際案例:
1、計時函數產生的異步問題:

function f1(){
  console.log("第一個");
}
function f2(){
  setTimeout(function(){
    console.log("第二個");
  },0);     //時間爲0,整個操作也是異步的
}
function f3(){
  console.log("第三個");
}
f1();
f2();
f3();

(1)ES4/ES5解決方案:使用回調函數解決。
將異步操作的內容進行改造,設置一個回調函數作爲參數保證同步性。

 function f1(){ console.log(F1); }
     function f2(callback){     //函數作爲形參
       window.setTimeouut(function(){
         console.log(F2);
         callback();
},2000);
}
     function f3(){ console.log(F3); }
     //執行上述函數並保證F1 F2 F3的時序性
     f1();
     f2(f3);   //將函數名f3傳遞給形參callback,callback成爲了函數f3的一個引用

(2)回調函數作爲參數:
 可以是一個已經定義好的函數名。
 可以是一個當時定義的匿名函數。

  f1();
      f2(function(){
        //可以書寫想與f2函數的執行內容同步的任意代碼
        var m=100,n=1000;
        console.log(m+n);
})
      實際應用:jQuery中有一個方法 animate({},duration,callback)
      $(“#ball”).animate({
        “margin-left”:+=200px”
},2000,function(){
  // 當動畫結束之後執行該函數內部的代碼
})

(3)當有兩個異步操作時如何通過回調函數處理:

function f1(){
	console.log("第一個");
}
function f2(callback,callback2){
	window.setTimeout(function(){
		console.log("第二個");
		callback(callback2);
	},2000)
}
function f3(callback){
	window.setTimeout(function(){
		console.log("第三個");
		callback();
	},5000)	
}
function f4(){
	console.log("第四個");
}
f1()
f2(f3,f4)

** 結論:回調函數容易造成“回調地獄”。**
2、資源加載的異步問題:

 // var imgNode = document.createElement("img");
var img=new Image();
img.src="images/06.jpg";
pic.appendChild(img);

console.log(img.width);    //0
console.log(img.height);   //0

解決方案:可以將輸出涉及到資源的代碼書寫在資源的onload事件中,若資源加載失敗,
可以將加載失敗後執行的代碼書寫在資源的onerror事件中。
例:利用回調函數將加載圖片的代碼進行封裝。

 function loadImage(parent,url,success,failure){
	  var img=new Image();
	  img.src=url;
	  parent.appendChild(img);
img.onload=function(){
		success();
	  }
img.onerror=function(){
		failure();
	  }
}

loadImage(box,"images/12.jpg",function(){
	console.log("圖片加載成功了");
},function(){
	console.log("圖片加載失敗了");
})

3、結論:回調函數可以解決異步問題。
四、ES6引入了Promise對象解決異步問題:
1、語法格式:

let promise = new Promise(function(resolve,reject){
    //書寫異步操作的代碼
    if(異步操作執行成功){
       resolve();
}
if(異步操作執行失敗){
   reject();
}
})

promise.then(function(){
   //書寫調用了resolve()時執行的代碼
},function(){
   //書寫調用了reject()時執行的代碼
})

2、例1:加載一張圖片,在圖片加載成功後輸出圖片的寬度和高度,若圖片加載失敗則顯示
加載失敗的文本提示。

let promise=new Promise(function(resolve,reject){
	var img=new Image();
	img.src="images/2.jpg";
	box.appendChild(img);
	img.onload=function(){
		resolve(this);
	}
	img.onerror=function(){
		reject();
	}
})

promise.then(function(obj){
	console.log(`圖片寬度=${obj.width}`);
	console.log(`圖片高度=${obj.height}`);
},function(){
	console.log("圖片加載失敗");
})
 3、例2:利用Promise封裝加載一張圖片的功能。
function loadImage(parent,url){
	return new Promise((resolve,reject)=>{
		var img=new Image();
		img.src=url;
		parent.appendChild(img);
		img.onload=function(){
			resolve(this);
		}
		img.onerror=function(){
			reject();
		}
	})
}

loadImage(box,'images/3.jpg').then(function(obj){
	console.log("圖片加載成功");
	console.log(obj.width);
}).catch(function(){
	console.log("圖片加載失敗");
})

** 4、例3:封裝confirm()。**

function $confirm(message){
	return new Promise((resolve,reject)=>{
		let temp=window.confirm(message);
		if(temp){
			resolve();
		}else{
			reject();
		}
	});
}

$confirm("您確定關閉嗎?").then(()=>{
	console.log("關閉了");
}).catch(()=>{
	console.log("取消了");
})

5、Promise技術解決異步問題的優勢:
(1)可以有多個then()連綴書寫。
(2)Promise技術避免了回調地域。
(3)不僅給出了異步操作成功的代碼解決方案,還給出了異步操作失敗和完成的解決
方案。

new Promise(function(resolve,reject){
  //異步操作
}).then(function(){
  //異步操作成功
}).catch(function(){
  //異步操作失敗
}).finally(function(){
  //異步操作完成
})

6、例4:加載多個圖片。

  • 當所有圖片都加載成功後,輸出“所有圖片加載成功”;有任意圖片沒有加載成功,輸 出“有圖片沒有加載成功”。
  • 靜態方法:Promise.all(array)
  • 功能:返回一個Promise實例,參數array是一個元素爲Promise實例的數組。當數組中所有的Promise實例均執行resolve()方法後,整個Promise實例纔會表示成功。
  • 靜態方法:Promise.race(array)
  • 功能:與Promise.all()相反。
let imgs=['1.jpg','2.jpg','30.jpg','4.jpg'];
let pro=[];
for(let i=0;i<imgs.length;i++){
	let temp = loadImage(box,'images/' + imgs[i]);
	pro.push(temp);
}

Promise.all(pro).then(()=>{
	console.log("所有圖片都加載成功了");
}).catch(()=>{
	console.log("有圖片沒有加載成功");
})

** 7、封裝Ajax技術:**
(1)原生JavaScript:XMLHttpRequest()
(2)jQuery:$.ajax()
(3)Vue.js:axios
(4)小程序:wx.request()
如何利用Axios技術提交一個Ajax請求:

 	$axios.get(url,{}).then().catch();
    $axios.post(url,{}).then().catch();

**問題:**因爲$axios後面還要跟具體的不同而兩個方法(get()、post()),所以不能使
用function進行封裝。
解決:使用類封裝(混合模式:屬性定義在構造函數中,方法定義在原型下)。

 // 先創建構造函數
function Axios(){}

// 創建Axios類的方法
Axios.prototype.get=function(){
}
Axios.prototype.post=function(){
}

// 創建Axios類的實例
let $axios = new Axios();

$axios.get();      //發送get請求
$axios.post();     //發送post請求

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章