---
###### tags: `Game`
---
# 12/01
### 回調地獄
```typescript=
function doSomeThing(t: number, cb: any) {
return () => {
if (--t === 0) {
logA(() => {
logB(() => {
logC();
});
});
}
};
}
function logA(cb: any) {
console.log("第一種回調");
cb();
}
function logB(cb: any) {
console.log("第二種回調");
cb();
}
function logC() {
console.log("第三種回調");
}
```
## Promise 承諾
- 異步請求,同步結果
- 實現承諾 (resolve)、違背承諾(reject)、承諾等待中(pending)
- ==Promise 是解決異步流程化的一種手段==
- 異步本身就是互不相干,你做你的我做我的,但流程化就是使用異步方法的時候需要走一個先後順序
- 兩個 ajax 本身都是(異步)請求,但 B 需要等待 A 的結果再做請求(流程)
- Promise 本身是同步
- Promise 構造函數 需要 new
- Promise 參數 executor 執行器
- executor -> resolve、reject 函數
- executor new Promise 調用
```typescript=
// executor 是同步執行
let promise = new Promise((resolve, reject) => {
console.log(1);
throw new Error("Err:承諾石沉大海");
resolve("承諾實現");
reject("承諾石沉大海");
});
// then 是異步調用
promise
.then((res) => {
console.log("Then");
})
.then(() => {
console.log("Then2");
})
.then(() => {
console.log("Then3");
})
.catch((err) => {
console.log("捕捉", err);
});
console.log("外面");
```
```typescript=
readFile(userPath)
.then((res) => {
console.log(res);
// 語法糖
// return new Promise((resolve,reject)=>{ resolve("成功") })
return Promise.resolve("成功");
})
// 返回一個狀態
.then((res) => {
console.log(res);
});
```
## 實作
:::info
需求:現在有三種 json 資料如圖一,使用 fs 整理如圖二
- 圖一

- 圖二

:::
### CallBack 版
```typescript=
// 讀取 user.json 資料
fs.readFile(userPath, "utf-8", (err, data) => {
const userData: user[] = JSON.parse(data);
const userInfo: user = userData.filter((item: user) => {
return item.id === uid;
})[0];
// 讀取 userCourse.json 資料
fs.readFile(userCoursePath, "utf-8", (err, data) => {
const userCourseData: userCourse[] = JSON.parse(data);
const userId = userInfo.id;
const userCourse: userCourse = userCourseData.filter((item: userCourse) => {
return item.uid === userId;
})[0];
// 讀取 course.json 資料
fs.readFile(coursePath, "utf-8", (err, data) => {
const courseData: course[] = JSON.parse(data);
const userCourses = userCourse.course;
let arr: any = [];
// 比對後放進 arr
userCourses.map((id) => {
courseData.map((item) => {
if (item.id === id) {
arr.push(item);
}
});
});
const userCourseInfo = {
username: userInfo.username,
course: arr,
};
const path1 = path.resolve(
__dirname,
`../data/${userInfo.username}.json`
);
// 寫入檔案
fs.writeFileSync(path1, JSON.stringify(userCourseInfo));
});
});
});
```
### Promise 版
```typescript=
// 定義一個 Promise 函數
function readFile(path: string, prevData?: any): Promise<any> {
return new Promise((resolve, reject) => {
fs.readFile(path, "utf-8", (err, data) => {
if (err) {
reject(err);
}
const resData = JSON.parse(data);
resolve({
prevData,
resData,
});
});
});
}
```
```typescript=
// 讀取 user.json 資料
readFile(userPath)
.then((res: any) => {
const { resData } = res;
const userInfo: user = resData.filter((item: user) => {
return item.id === uid;
})[0];
return readFile(userCoursePath, userInfo);
})
// 讀取 userCourse.json 資料
.then((res: any) => {
const { prevData, resData } = res;
const userId = prevData.id;
const userCourse: userCourse = resData.filter((item: userCourse) => {
return item.uid === userId;
})[0];
return readFile(coursePath, {
username: prevData.username,
userCourse,
});
})
// 讀取 course.json 資料
.then((res) => {
const { prevData, resData } = res;
const userCourse = prevData.userCourse.course;
let arr: any = [];
userCourse.map((id: number) => {
resData.map((item: any) => {
if (item.id === id) {
arr.push(item);
}
});
});
const userCourseInfo = {
username: prevData.username,
course: arr,
};
const path1 = path.resolve(__dirname, `../data/${prevData.username}.json`);
// 寫入檔案
console.log("正在寫入檔案");
fs.writeFileSync(path1, JSON.stringify(userCourseInfo));
})
.catch((err) => {
console.log(err);
});
```
### async await 版
- function 不需要 prevData
```typescript=
// 讀取 user.json 資料
async function getData(uid: number) {
// 讀取 user.json 資料
const res = await readFile(userPath);
const userInfo: user = res.filter((item: user) => {
return item.id === uid;
})[0];
// 讀取 userCourse.json 資料
const res_1: userCourse[] = await readFile(userCoursePath);
const userId = userInfo.id;
const userCourse = res_1.filter((item) => {
return item.uid === userId;
})[0];
// 讀取 course.json 資料
const res_2: course[] = await readFile(coursePath);
const userCourse_2 = userCourse.course;
let arr: course[] = [];
userCourse_2.map((id) => {
res_2.map((item) => {
if (item.id === id) {
arr.push(item);
}
});
});
const userCourseInfo = {
username: userInfo.username,
course: arr,
};
const path1 = path.resolve(__dirname, `../data/${userInfo.username}.json`);
// 寫入檔案
console.log("正在寫入檔案");
fs.writeFileSync(path1, JSON.stringify(userCourseInfo));
}
```
## Promise.all()
:::info
- 需求:合併三個文件內部的內容為一個陣列,並且按照順序排列
- 如果一個讀取失敗,讓這個數據集合返回一個 rejected
:::
```typescript=
// 法A 逐步處理
readFile(userCoursePath).then((res) => {
console.log(res);
});
readFile(coursePath).then((res) => {
console.log(res);
});
readFile(userPath).then((res) => {
console.log(res);
});
// 法B Promise.all()
// 接收參數 iterable 類型的數據 -> Array Set Map
Promise.all([
readFile(userCoursePath),
readFile(coursePath),
readFile(userPath),
]).then((res) => {
console.log(res);
});
```
- 用多個異步任務併發運行,他的結果創建承諾之後使用,等待所有任務的結果完成
- iterable 內部元素傳遞的是 promise 物件集合
- 如果不是 promise,直接 resolve Promise.resolve(0||'123'||true)
- iterable 內部沒有元素,返回空陣列
- 有一個 promise 是 rejected 實例回調 rejected
- 失敗的原因:是第一個產生的 Error
## Promise.race()
- 圖片資源載入速度,或者 api 測試
```typescript=
// 誰先完成就返回那個 promise的結果,無論是 full filled 還是 rejected
// 測試資源或者接口響應速度
Promise.race([
readFile(userCoursePath),
readFile(coursePath),
readFile(userPath, true),
])
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
```
## async await
- await 是一個操作符
- 等待一個 Promise 物件產出結果的操作手段
- 功能是暫停 async 函數的執行,等待 Promise 處理後的結果
- 假如 Promise 處理的結果是 reject,會拋出異常
- async 函數式通過一個隱式的 Promise 返回 pending 狀態
- 處理 Promise 結果使用 async await
```typescript=
// async 的意思是當前這個異步與同一作用域下的程序是異步的關係
async function logData() {
const p1 = await getData();
const p2 = await getData(p1);
const p3 = await getData(p2);
const p4 = await getData(p3);
const p5 = await getData(p4);
const p6 = await getData(p5);
}
```
- 轉變 前、後

### Promise A+規範
- 讀 官方文件 Promise A+規範
- 手寫一個 基本的 MyPromise
```typescript=
class MyPromise {
private status;
private value: any;
private reason: any;
constructor(
executor: (
resolve: (value: unknown) => void,
reject: (reason?: any) => void
) => void
) {
this.status = "Pending";
this.value = undefined;
this.reason = undefined;
const resolve = (value: any) => {
if (this.status === "Pending") {
this.status = "Fulfilled";
this.value = value;
}
};
const reject = (reason: any) => {
if (this.status === "Pending") {
this.status = "Rejected";
this.reason = reason;
}
};
executor(resolve, reject);
}
then(onFulfilled: any, onRejected?: any) {
if (this.status === "Fulfilled") {
onFulfilled(this.value);
}
if (this.status === "Rejected") {
onRejected(this.reason);
}
}
}
let myPromise = new MyPromise((resolve, reject) => {
resolve("test");
reject("Err");
});
myPromise.then(
(value: any) => {
console.log("已完成 : " + value);
},
(reason: any) => {
console.log("被拒絕 : " + reason);
}
);
```
- ==感覺有點深,先跳過==
- [JavaScript Promise | 從 Promises/A+ 規範瞭解 Promise](https://medium.com/%E6%89%8B%E5%AF%AB%E7%AD%86%E8%A8%98/promises-a-plus-330dda203569)
-