3C科技 娛樂遊戲 美食旅遊 時尚美妝 親子育兒 生活休閒 金融理財 健康運動 寰宇綜合

Zi 字媒體

2017-07-25T20:27:27+00:00
加入好友
年前有個朋友面試,遇到了同步和非同步的問題。這幾年 JavaScript 也從 callback,慢慢演進到許多非同步的解法。 之前有提過 JavaScript 是一門有點 FP(Functional Progrmming)的語言,而 FP 把函式當成 first class(一等公民),所有的 function 都可以當成一種物件、當成一種參數來傳遞。像是你可以寫出這樣子的程式碼: const onSuccess = (res) => { if (res.result === 0) { console.log('登入成功'); } else { console.log('登入失敗'); } }; login('username', 'password', onSuccess); } 但你可能會比較習慣 callback 的形式,直接把那個 function 放在參數裡面,不另行宣告: login('username', 'password', (res) => { if (res.result === 0) { console.log('登入成功'); } else { console.log('登入失敗'); } }); callback 是個很棒的寫法,可以很容易地看出哪個 function 執行完之後要做什麼事情。不過 callback 一多,縮排就會很醜: login('username', 'password', (res) => { if (res.result === 0) { getPosts(res.uid, (posts) => { if (posts && posts.length) { console.log('你的文章有 ' + posts.length + ' 篇'); } else { console.log('沒有文章'); } }); } else { console.log('登入失敗'); } }); 然後再多幾個 callback 就會變成龜派氣功了。這就是俗稱的 Callback Hell。 這裡(callbackhell.com) 有幾個做法教你如何避免 Callback Hell,像是宣告好函式然後拆開使用之類的。不過接下來要講的 Promise,才是 JS 試圖解決 Callback Hell 的方法。 Promise 有了 Promise 以後,你就可以把剛剛那段 code 改寫成這樣: loginAsync('username', 'password') .then((res) => { if (res.result === 0) return getPostAsync(res.uid); return console.log('登入錯誤'); }) .then((posts) => { if (posts && posts.length) { console.log('你的文章有 ' + posts.length + ' 篇'); } else { console.log('沒有文章'); } }); 可以像發動遊戲王卡的陷阱卡一樣一步一步串(chain)起來,只要用一個 Promise 把原先的動作包起來就好了。 而寫一個簡單的 Promise 可以這樣做: const logAsync = (message, time) => { return new Promise((resolve, reject) => { if (message && time) { setTimeout(() => { console.log(message); resolve() }, time); } else { reject(); } }); }; 主要是回傳一個 Promise,Promise 裡面放著要執行的 function,然後成功的話呼叫 resolve 方法、失敗的話呼叫 reject 方法。這樣就可以把方法 chain 起來: logAsync('這個訊息過一秒才會出現', 1000) .then(() => { return logAsync('這個訊息再過 1.5 秒才會出現', 1500); }) .then(() => { return logAsync('這個訊息再過 2 秒才會出現', 2000); }); 前往 此篇文章完整版 或到 CodePen 上查看程式碼 原本就存在的 function 可以以類似的方法用 Promise 包起來,這樣就能用 then 的方式連續呼叫多個方法了。 Promise 其實還有不少用法,之後有機會再開番外篇來介紹。這篇提 Promise 主要是為了後面的 async/await 鋪路,這才是 JS 非同步潮的地方。 你可能還聽過 generator,但現在其實很少用到這東西了。建議你學 async/await 就好了。 Async/await async function 是不管怎樣都會回傳 Promise 的函式。例如: const foo = async () => { return 1; } foo().then((res) => { console.log(res); }); 雖然我們的 foo 回傳的不是一個 Promise,但因為它是 async function 的關係,JS 會自動把它包成 Promise,所以可以使用 then,結果會得到 1。 而 await 則是可以等 Promise 執行完再執行下一行: const demo = async () => { await logAsync('1 秒後會出現這句', 1000); await logAsync('再 1.5 秒後會出現這句', 1500); await logAsync('再 2 秒後會出現這句', 2000); }; demo(); 不過 await 必須在 async function 裡面才能使用。 前往 此篇文章完整版 或到 CodePen 上查看程式碼 而且 await 也能夠把 Promise 回傳的值接起來,通常我們在呼叫 API(例如執行 fetch、axios)的時候就很好用: (async () => { const res = await fetch('API_URL'); const data = await res.text(); console.log(data); })(); 搭配 axios 更可以這樣使用: ((async () => { const { data } = await axios.get('API_URL'); console.log(data); })(); 前往 此篇文章完整版 或到 CodePen 上查看程式碼 結語 使用 async/await 呼叫 API 或是其他非同步方法,不但可以避免 Callback Hell,比起 Promise 更增加了程式可讀性(這點見仁見智就是了),是個我覺得寫 JS 的朋友都應該會的東西。 最後,我覺得如果第一次碰 async/await,還是多看幾篇文章,看看不同人的觀點。我第一次碰這東西也是寫的霧煞煞,所以推薦幾篇文章: 鐵人賽:JavaScript Await 與 Async 告別 JavaScript 的 Promise!迎接 Async/Await 的到來 How To Master Async/Await With This Real World Example 第一篇先到這邊,下一篇來講運算子、選擇結構和函式。 我要學會 JS 目錄 我要學會 JS(一):JavaScript 簡介 我要學會 JS(二):基本運算與結構 我要學會 JS(三):callback、Promise 和 async/await 那些事兒 待續...

本文由noobtw提供 原文連結

寫了 5860316篇文章,獲得 23313次喜歡
精彩推薦