Javascript- 同步與非同步
目錄
同步執行(Synchronous execution)
任務會一個接一個有序執行
異步/非同步執行(Asynchronous execution)
執行超長任務,例如發送請求/給出回應。如果執行任務時間過長則會產生堵塞,導致無法執行其他任務,因此會一邊執行超長任務一邊執行其他任務。
setTimeout
讓代碼經過特定時間點再執行
setTimeout(function() {} , ms)
settTimeout會形成closure,並將值儲存起來,當觸發到timer時再執行
常見問題
如何使用setTimeout,間隔一秒print出1~5
function printDigit() {
for (var i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i);
}, i * 1000);
}
console.log('Hello');
}
printDigit();
// Output:
//Hello
// 6
// 6
// 6
// 6
// 6
在上面的代碼中,setTimeout會儲存函式內容直到(timer),而我們設定的值都指向同一個參考值i,而不是i本身的值(1~5)。
當內部函式完全跑完五次迴圈(此時參考值都還是i),直到i=6跳出迴圈並執行callback,因此會print出6
解法
解法1:改用let讓變數具block scope(區塊作用域)性質,每一次疊代i都會產生新的值,因此迴圈執行的時候也是參考新的i值,setTimeout儲存的是由i=1,2,3..所執行的closure,所以print出來的數字互相獨立。
function printDigit() {
for (let i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i);
}, i * 1000);
}
console.log('Hello');
}
printDigit();
// Output:
//Hello
// 6
// 6
// 6
// 6
// 6
解法2:一樣使用var的解法
function printDigit() {
for (var i = 1; i <= 5; i++) {
function close(i) {
setTimeout(function () {
console.log(i);
}, i * 1000);
// 將setTimeout放在新的Fn內
}
close(i); //每次呼叫都會產生新的i
}
console.log('Hello');
}
printDigit();
綜合題
以下分別會print出哪些東西?
//
for (var i =0; i<=2 ; i++) {
setTimeout(function fn() {
console.log(`var, i<=2, i:`+i)
}
,1000)
}
//var, i<=2, :2
//var, i<=2, :2
//var, i<=2, :2
for (var i =0; i<2 ; i++) {
setTimeout(function fn() {
console.log(`var, i<2, i:`+i)
}
,1000)
}
//var, i<2, i:2
//var, i<2, i:2
for (let i =0; i<=2 ; i++) {
setTimeout(function fn() {
console.log(`let, i<2, i:`+i)
}
,1000)
}
//let, i<2, i:0
//let, i<2, i:1
//let, i<2, i:2
callback
將函數作為參數傳遞 =>確保執行函式的順序
當程式太複雜或太多層串在一起會難閱讀,bug出現很難維護=>callback地獄
promise
編寫代碼更簡潔且容易維護,有三種狀態
- resolve:履行
- reject:拒絕
- pending:待定
let p = newPromise(resolve, reject) {
if( condition ) {
resolve(要返回的字串或是陣列等等) //代表完成請求
} else{
reject(要返回的值或是陣列等等)//代表請求被拒絕
}
p
.then(function() {
})
//之後要執行的動作,function的參數就是由resolve返回的值
.catch(..)
//發生錯誤時執行的動作,function的參數就是由reject返回的值
常用在fetch
const f = fetch("apiurl")
f
.then(function(data) {
return data.json()//將原始數據轉換成json格式
由於json()也是promise,無法直接獲取,需要用return給下一個then
})
//
.then(function(jsonData) {
console.log(jsonData)
})
//得到最終格式並print出結果
promise chain
async/await
提供更加直觀的代碼
- async:定義函式為異步
- await:只有在async內才能使用
function sendRequest() {
newPromise(resolve, reject) {
if( condition ) {
resolve("request is sent")
} else{
reject("request is failed")
}}
async function getResult() {
try{
let data = await sendRequest()
console.log(data)
}
catch (errer) { //捕捉錯誤,失敗時執行的動作
console.log(error)
}
getResult()
用於fetch的方式
//使用promise
const f = fetch("apiurl")
f
.then(function(data) {
return data.json()
})
.then(function(jsonData) {
console.log(jsonData)
})
//使用async/await
async function getData() {
try {
let userdata = await fetch("apiurl");
userdata = await userdata.json()
console.log(userdata)
} catch(message) {
console.log(message)
}
}
getData()
Comments