1.介紹promise和模仿Promise.all和Promise.race
promise的設計主要是解決回調地獄(接收結果用回調函數來處理,但必須傳入回調函數)的問題,由一層層嵌套回調函數改為由then來執行。
例如:
// callback用于接收傳回結果, 異步方式
fs.readFile("filePath", callback);
// 還有一種方式
cosnt { promises: fs } = require("fs"); // 用promise包裝fs子產品,已經實作
fs.readFile("filePath").then(callback);
// 由上可看出,promise隻是解決了回調函數的調用方式,沒有徹底改變回調函數繼續存在的問題。
promise有三個狀态,分别是pending, resolve,reject。隻有resolve或者reject被調用,才會結束。
promise對象可以通過new建立, 結果傳回後then和catch方法會調用,resolve和reject會走then方法,catch是捕捉未處理異常的方法(比如:500,404之類)。
值得注意的是,then方法的傳回值為promise類型,如果在then中繼續執行異步操作,則可以在then後面再次寫一個then操作。叫做鍊式調用,例如:Promise.resolve("success") .then((res) => "異步操作") .then((resSecond) => console.log(resSecond)); // resSecond為“異步操作”
另外可直接調用resolve狀态或者reject狀态,例如Promise.resolve(),或者Promise.reject()方法。這兩個方法直接傳回結果,也可以傳入一個Promise對象或者工廠函數。這兩個函數本質都是内部建立了一個Promise對象,調用resolve或者reject。
現如今很多的異步請求,異步執行方式,都在向promise靠攏。提供了很多的便利性。比如:axios,上面提到的fs子產品,等等。我用過angular的subscribe,也是對異步的一種處理方式。但有點不倫不類。
1.1 模拟異步操作,用于測試
// 模拟異步請求
const suc = function (time: number) {
return new Promise(resolve => {
setTimeout(() => {
// time秒鐘之後傳回結果
resolve("success");
}, time);
})
}
const rej = function (time: number) {
return new Promise((resolve, reject) => {
setTimeout(() => {
// time秒之後拒絕
reject("fail");
}, time);
})
}
// 以上代碼也可合并為一個函數,請讀者自行考慮。
1.2 Promise的all,race方法模拟
PromiseAll方法内内隻接受兩個異步Promise,算是簡化版了(官網api代碼簡介),能力有限。PromiseRace基本和官網上的差不多。
PromiseRace: 競争性關系,擷取第一個結果(無論結果resolve或者reject),立即傳回。
PromiseAll_2:感覺使用狀态控制這種不是太好啊
// 準确來說,這個方法有缺陷,隻要第一個傳回,不管對與不對都傳回,應該是所有結果都被reject掉才會傳回reject,隻有一個正确都要傳回正确結果。可結合PromiseAll_2看
function PromiseRace(arrs: Array): Promise {
if (arrs.length === 0) return Promise.resolve([]);
return new Promise((resolve, reject)=> {
arrs.forEach((pro) => {
Promise.resolve(pro).then(resolve, reject);
});
});
}
// 當所有結果為ture,才會傳回ture
function isAllFulfilled(states: Array): boolean {
let res: boolean = true;
states.forEach(state => res = res && state)
return res;
}
// 用一種循環的方式疊代每個異步方法,如果不是函數或對象就直接作為結果傳回
function PromiseAll_2(arrs: Array): Promise {
if (arrs.length === 0) return Promise.resolve([]);
const states: Array = Array.from({length: arrs.length}, (item) => item = false);
return new Promise((resolve, reject)=> {
const result = [];
arrs.forEach((pro, index) => {
// 對輸入做一個封裝,如果是常數或者不是promise的這樣就直接傳回
Promise.resolve(pro).then(res => {
states[index] = true;
result[index] = res;
if (isAllFulfilled(states)) resolve(result);
}, err => reject(err));
});
});
}
function PromiseAll(one: Promise, two: Promise): Promise {
return new Promise((resolve, reject) => {
let twoRes = null;
let oneRes = null;
// 基于兩個異步互相檢測,官網那個有點看不大明白。各位有什麼好的代碼建議不妨評論說一下
one.then((res) => {
oneRes = res;
if (twoRes) resolve([oneRes, twoRes]);
}, (err) => reject(err));
two.then((res) => {
twoRes = res;
if (oneRes) resolve([oneRes, twoRes]);
}, (err) => reject(err));
});
}
PromiseAll(suc(1000), rej(2000)).then((res) => {
console.log(res);
}).catch((err) => console.log(err));
1.3 小工具。
- 使用promisify對settimeout做個封裝,單純隻是延遲執行
const util = require("util"); // 封裝settimeout延遲執行 const delay = util.promisify(setTimeout); // 用作延遲執行,一般在await的時候用 用例: async function test() { await delay(1000); // 延遲一秒執行 }
- async簡單介紹
async徹底解決了異步操作回調函數問題。 隻需使用await關鍵字,就會等待異步操作執行完畢才會繼續執行後續代碼。把異步操作 變為同步操作。
// 代碼
async function test() {
const { data } = await axios.get("http://www.baidu.com"); // { data }為解構指派
// do something
}
// 不用async
function test() {
axios.get("http://www.baidu.com").then((res) => {
console.log(res.data);
//do something
});
}
// 對比以上結構,async函數的同步會帶來很大的友善,但在加載網頁的時候可能需要等待。
// 如果不希望頁面卡頓,采用異步還是比較好的。
2. 每周分享
- 前端架構和es的一些變化,這裡面介紹的是前端中最近的一些架構或者基礎性知識。
- nginx的基礎入門,對nginx的一個用法基本介紹。
-
阿裡AI labs研發“智能防騷擾電話技術”,當接聽到騷擾電話時,可以轉到機器人接聽。我試了一下,聽得我一愣一愣的,還以為真的和人工客服聊天。具體想體驗的可以在支付寶搜尋天貓精靈。不過這項功能可能會給你帶來困擾,如果你主動挂斷電話,就會立馬改為由智能機器人接聽,如果是你女票打來的,你有事情馬上挂斷,後果不堪設想!好在可以關閉或者打開。玩玩可以,可不要貪杯啊。(>_<)
----
資料
- MDN,關于peomise的解析
- 官網api代碼簡介