Promise 最核心的地方就放在這篇了。
fetch 回傳的是一個 Promise
1 | const url = 'https://api.com'; |
這就跟 $('.btn') 會回傳 jQuery 物件,new Date() 會回傳 Date 物件,/yo/ 會回傳 RegExp 物件是一樣的道理。fetch 也會回傳一個物件,這個物件就叫做 Promise。
但要注意並不是只有 fetch 才會回傳 Promise,fetch 只是其中之一而已。
例如以下回傳的也是 Promise:
1 | // 讀取存在剪貼簿的值(Ctrl+C) |
怎麼從 Promise 物件拿到結果
要用 Promise 提供的 .then 方法來取得,裡面傳的是一個 callback function:
1 | const url = 'https://api.com'; |
結果大概長這樣:
1 | Response { |
這時候就會很疑惑「居然沒辦法看到 body?」,這是因為從 then 裡面拿到的東西也是一個物件,我不確定它實際上叫做什麼,但總之先叫它 Response 吧。
如果要看到 body 的內容的話得用 Response 物件提供的方法,最常見的有兩種:
response.text()response.json()
結果這樣寫之後又會發現:「靠腰,怎麼又是 Promise」
1 | fetch(url) |
沒錯,這就是 Promise 的套路,通常在 Promise 裡會再回傳另一個新的 Promise。
但是不用想太複雜,這個就跟 jQuery 可以一直 $(.btn).find('.aa').css() 的道理有點像。為什麼可以一直這樣 . 下去?因為每一次的回傳值都是 jQuery 物件。
所以如果要再從 Promise 裡面拿到結果,就要再用 then 來拿:
1 | fetch(url) |
為什麼可以 then 再接 then
因為 then 這個方法回傳的也是一個 Promise…
而且在 then 裡面「回傳的東西」會是「下一個 then 裡面會拿到的值」。這一段很重要,所以麻煩記起來,拜託拜託。
以上面的例子來示範:
1 | fetch(api500) |
再來是另外一個重點,如果在 then 裡回傳的也是 Promise,那下一個 then 拿到的會是Promise 解析後(做完 then 後)的值
一樣示範一次:
1 | fetch(url) |
這個就是 Promise 最大的優勢了,為什麼?你比較看看這兩段程式碼:
1 | // 第一個 |
第一個寫法根本就是 callback hell,但第二個寫法就改善這問題了,因為它把層數壓低了。
可是為什麼能這樣子?原理就是剛剛講的,如果在 then 裡面回傳 Promise 的話,下一個 then 就會拿到解析後的結果。
這點還蠻有趣的,網路上確實只會教你第二種寫法,但很少人告訴過你為什麼可以這樣子。總之,相信現在你應該能理解了。
來做個總結
複習一下 Promise 的幾個特性:
- 要拿到 Promise 的結果要用
then then本身會回傳 Promise,所以可以一直then下去then裡面回傳什麼,下個then就會拿到什麼- 如果
then裡回傳的也是 Promise,下個then拿到的就會是 Promise 解析後的值