Javascript- 同步與非同步

J
J 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()
ref:

Comments