所謂的「Callback function」,簡單來說就是「把函式當作另一個函式的參數,透過另一個函式來呼叫它」。
大部分使用callbacks(回調)函式的是非同步執行,但並非所有都是非同步。
同步的Callback function:
非同步的Callback function:
範例:
function getData(name, callback) {
setTimeout(() => {
callback({
name:name,
age:Math.floor(Math.random()*10),
sex:"male"
})
},2000)
}
console.log("start");
getData("Harry",(obj) => {
console.log(obj);
});
console.log("end");
執行結果:
但過多的Callback function會造成難以閱讀的Callback Hell,一步一步串下去,缺點是閱讀困難。
ES6出現的語法,Promise是一個物件,透過new
來建立Promise
的建構式。
能表示非同步運算的操作最後是完成或失敗,用resolve
與reject
來決定結果,可應用在連接資料庫時回傳Promise,且不需要再執行Callback,只要拿到它的Promise就好。
成功完成時:執行resolve,回傳Promise物件,作業結果的值被呼叫,取得資料。
執行錯誤時:執行 rejects,Promise會被拒絕,出現失敗訊息。
語法:
//executor function,代表一個接收resolve及reject的函式
new Promise( executor function(resolve, reject) {
... ...
}
);
executor function:語法出現的executor function,單純代表一個接收resolve
及reject
的函式,接收到resolve及reject後會立刻執行,函式名稱可匿名或自取名。
用new
來建立Promise
的建構式,是同步,會馬上執行。resolve
與reject
函式,會在被個別呼叫時,個別執行,所以.then()
裡面的回呼函式是非同步。且.then() 和 .catch() ,都會把 callback 給 Promise 化。
通常 executor function 會發起一些非同步操作,(例:setTimeout
、setInterval
......)。
一個 Promise
物件會有這些狀態:
resolve:裡面是你要的資料,成功時它會把這資料回傳給你,Promise 函式呼叫時使用 .then() 來接收 resolve 的結果,.then() 讓callback可以在非同步運算結束後呼叫
reject:裡面是顯示失敗的訊息,Promise 函式呼叫時使用.cach()來接收reject的結果。
Promise使用resolve的結果:
//用new建立Promise建構式
let example = new Promise((resolve,reject) => {
resolve({
name:"Harry",
age: 20});
});
example.then((d) => {
console.log(d);
});
執行結果:執行成功,所以顯示resolve裡的資料內容
使用reject,用.cach接住:
let example =new Promise((resolve,reject) => {
reject(new Error("not allowed"));
});
example
.then((d) => {
console.log(d);
})
.catch((e) => {
console.log(e);
});
執行結果:出現錯誤訊息
用Promise來改寫Callback:
//Callback
function getData(name, callback) {
setTimeout(() => {
callback({
name:name,
age:Math.floor(Math.random()*10),
sex:"male"
})
},2000)
}
console.log("start");
getData("Harry",(obj) => {
console.log(obj);
});
console.log("end");
//Promise寫法
function getData2(name) {
if (name == "Harry") {
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve({
name:name,
age:Math.floor(Math.random()*10),
sex:"male"
},2000);
});
})
} else {
return new Promise((resolve,reject) => {
setTimeout(() => {
reject(new Error("Not allowed to access data."));
},2000);
});
}
}
console.log("start2");
getData2("Harry2")
.then((obj) => {console.log(obj);})
.catch((e) => {console.log(e);})
console.log("end2");
執行結果:給getData2的參數是Harry,不等於Harry2,所以是reject的結果
Day19-JavaScript Promise 系列-更多關於 Promise 的練習
回呼常用來延續非同步行動完成後的程式執行:這就叫做非同步回呼
JavaScript Promise 類的實作與逐步解說
回呼函式 - 術語表 | MDN