2020年11月11日 星期三

javascript 如何建立一個 function ,於多個 Response 的資料都取完後才執行

紀錄一下在 javascript 如何建立一個 function ,於多個 Response 的資料都取完後才執行。

下面範例都是執行以下3個 request

URL Parameter Method
/get a=b&a=c&b=d GET
/post a=b&a=c&b=d POST
/anything POST

首先是最傳統的 ajax (為了方便,直接以 jQuery 來寫)

var i = 0
function callback(){
	if(i >= 3){
		// do something after all request finish
	}
	i++
}

$.get("/get", "a=b&a=c&b=d", callback)
$.post("/post", "a=b&a=c&b=d", callback)
$.post("/anything", callback)

之後我發現自 jQuery v1.5 , jQuery 追加了 when() function ,可以以以下方式來做到(為了方便, debug log 第幾個 request)

$.when(
	$.get("/get", "a=b&a=c&b=d", function(){console.debug(1)}),
	$.post("/post", "a=b&a=c&b=d", function(){console.debug(2)}),
	$.post("/anything", function(){console.debug(3)})
).then(function(){
	// do something after all request finish
	console.log('done')
})

之後 js 又追加 Promise 和 fetch() 這兩API

參照 Waiting for multiple all API responses to complete with the vanilla JS Promise.all() method 這篇文章,可以用以下寫法:

Promise.all([
	fetch('/get?a=b&a=c&b=d'),
	fetch(
		'/post', 
		{
			method: "POST", 
			body: (function(){
				var f = new FormData
				f.append("a", "b")
				f.append("a", "c")
				f.append("b", "d")
				return f
			})()
		}
	),
	fetch(
		"/anything",
		{
			method: "POST"
		}
	)
]).then(function (responses) {
	// Get a JSON object from each of the responses
	return Promise.all(responses.map(function (response) {
		return response.text();
	}));
}).then(function (data) {
	// do something after all request finish
}).catch(function (error) {
	// if there's an error, log it
	console.log(error);
});

順帶一提,第二條 fetch() 也能寫成

fetch(
	'/post', 
	{
		method: "POST", 
		body: "a=b&a=c&b=d",
		header: {
			"Content-Type": "application/x-www-form-urlencoded"
		}
	}
)

如果不想用 fetch(),可以參照《JavaScript Promise 全介紹》這篇文章,先建立 AJAX 的 Promise

function ajax(url, parameter, method = "GET") {
	return new Promise(function(resolve, reject){
		var xhr = new XMLHttpRequest()
		xhr.open(method, url)
		xhr.addEventListener("readystatechange", function(e) {
			switch(this.readyState){
				case XMLHttpRequest.DONE:
					resolve(JSON.parse(this.response))
					break
				case XMLHttpRequest.UNSENT:
					reject(new Error(xhr))
					break
				
			}
		})
		if(typeof parameter == "string" && method.toUpperCase() != "GET"){
			xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
			xhr.send(parameter)
		}else if(method.toUpperCase() != "GET"){
			xhr.send(parameter)
		}else{
			xhr.send()
		}
	});
}

然後用Promise.all()(一樣,為了方便,debug log 第幾個 request):

Promise.all([
	ajax("/get", "a=b&a=c&b=d").then((data)=>{console.debug(1); return data}),
	ajax("/post", "a=b&a=c&b=d", "POST").then((data)=>{console.debug(2); return data}),
	ajax("/anything", null, "POST").then((data)=>{console.debug(3); return data})
]).then(function(datas){
	// do somthing
	console.log(datas)
})

沒有留言:

張貼留言