前端培訓-中級階段(30)- Promise 對象(2019-12-19期)

前端最基礎的就是 HTML+CSS+Javascript。掌握了這三門技術就算入門,但也僅僅是入門,如今前端開發的定義已經遠遠不止這些。前端小課堂(HTML/CSS/JS),本着提高技術水平,打牢基礎知識的中心思想,咱們開課啦(每週四)。css

上一篇是使人吐槽的ES6,這一篇就有意思的多了。
異步操做咱們不陌生,瀏覽器的UI事件、AJAX、Worker、setTimeout、setInterval 等等都是異步操做。
那麼在執行異步操做時咱們都會放入一個回調,這裏有個名詞叫什麼來着?回調地獄
哈哈當咱們用 Promise 來處理的時候就簡潔多了,能夠鏈式操做。前端

回調與鏈式

舉個栗子吧,請求 A,用 A 的響應去請求 B,用 B 的響應去渲染到頁面上。git

代碼寫下面了,思考幾個問題es6

  1. 若是嵌套層級更深呢?
  2. 若是加上異常處理呢?
  3. 若是出現並行串行競爭等場景呢?

jQuery 中依賴 Deferred 實現。github

回調形式(JQuery)

$.ajax({
    url: 'https://www.lilnong.top/cors/A',
    success(data){
        $.ajax({
            url: 'https://www.lilnong.top/cors/B',
            data,
            success(data){
                $('body').text(JSON.stringify(data,null,4));
            }
        })              
    }
})

鏈式(Promise)(JQuery)

$.ajax({ url: 'https://www.lilnong.top/cors/A'})
.then((data)=>
    $.ajax({url: 'https://www.lilnong.top/cors/B',data})
)  
.then((data)=>
    $('body')
        .css('white-space', 'pre-wrap')
        .text(JSON.stringify(data,null,8))
)

Promise

建立 Promise

new Promise(function(resolve, reject) {...});

同步調用 function ,裏面能夠是執行同步的,也能夠執行異步的。面試

Promise狀態
初始狀態爲 pending
當邏輯執行完以後調用 resolve(data)(成功)、reject(失敗)來表示計算完成
調用以後 Promise 的狀態會改變爲 resolved(完成)、rejected(失敗)。
若是內部拋出異常,也會進入 rejected 狀態。ajax

測試代碼

new Promise((resolve, reject)=>{
    var start_time = Date.now();
    var dtime = Math.random()*1000;
    setTimeout(()=>{
        var end_time = Date.now();
        var query_time = end_time - start_time
        reject({start_time,dtime,end_time,query_time,now: Date.now()})
        resolve({start_time,dtime,end_time,query_time,now: Date.now()})
        console.log('promise', {start_time,dtime,end_time,query_time,now: Date.now()})
        return 'promise-return'
    }, dtime)
})
.then(v=>console.log('then',v))
.catch(v=>console.log('catch',v))

window.addEventListener('unhandledrejection',e=>console.log('event',e))

成功狀態

image.png
狀態不會被改變
image.pngjson

失敗狀態

reject 觸發狀態改變

image.png

拋出異常

image.png

方法內拋出異常

image.png

沒有catch,全局捕獲

image.png

總結

  1. functionreturn 的沒有被使用。
  2. 執行 resolvereject 並不會退出當前做用域,會繼續執行下面的代碼。
  3. resolvereject 執行以後,狀態和值就不會再被改變。即便報錯都不會改變
    image.png
  4. resolvereject 執行以後,回調被放入微任務隊列
  5. 若是 reject 狀態沒有被 catch 捕獲,那麼會觸發 unhandledrejection

Promise 方法

Promise.all(array)

返回一個新的 Promise 對象,根據 array 的結果來返回內容。segmentfault

當隊列中全部的 Promise 都成功纔會觸發成功返回一個新的 Promise 對象,參數是個數組,是對應 Promise 的返回值。順序是一 一對應的,和完成時間不要緊數組

當隊列中有任何一個 Promise 失敗則當即觸發失敗返回一個新的 Promise 對象。Promise.all(Array) 返回一個 Promise 對象。

假設 PromiseAll = Promise.all(PromiseArray)
如下表格爲 PromiseAll 在不一樣環境下的 不一樣狀態與值。

PromiseAll 狀態 PromiseAll 值
全部 Promise 都成功 resolved 原數組順序組成的 promise 返回值集合
有一個 Promise 失敗 rejected 第一個失敗的 Promise 的報錯信息

依賴這個方法咱們能夠解決前言中提出的問題,處理並行場景

Promise.race(array)

返回一個新的 Promise 對象,根據 array 的結果來返回內容。
當隊列中任意一個 Promise 的狀態變爲完成狀態(成功 resolved、失敗 rejected),則返回該 Promise。

依賴這個方法咱們能夠解決前言中提出的問題,處理競爭場景

Promise.reject(value)

返回一個狀態爲失敗的 Promise 對象。

Promise.resolve(value)

返回一個狀態由 value 決定的 Promise 對象
若是 value 是個 Promise 對象,那麼返回的就是該 Promise 對象。若是 value 不是 Promise 對象,那麼返回就是一個成功狀態的 Promise,值爲 value。

若是你不知道一個值是否是 Promise 對象,使用Promise.resolve(value) 來返回一個 Promise 對象,這樣就能安全的將該值當作 Promise 來使用了。

Promise.prototype.catch(onRejected)

當 Promise 失敗時會調用。

return 返回值的會做爲 resolve 狀態繼續傳遞。

Promise.prototype.then(onFulfilled, onRejected)

resolve 狀態時會執行 onFulfilled 回調。
rejected 狀態時會執行 onRejected 回調。若是沒有 onRejected 回調 那麼錯誤信息繼續傳遞。

return 返回值的會做爲 resolve 狀態繼續傳遞。

Promise.prototype.finally(onFinally)

resolve 和 rejected 狀態都會調用回調。可是有不一樣點

  1. 回調沒有參數。(resolve 的參數是傳遞或者 return 過來的,rejected 是傳遞或者拋出的異常。)
  2. 也不會覆蓋以前值
    image.png

其實能夠當作 try{}catch(e){} finally{}finally 來使用

await/async

await 操做符用於等待一個 Promise 對象。 await 只能在異步函數 async function 中使用。

上述的 Promise 只是把回調嵌套改爲鏈式扁平化,可是看上去仍是怪怪的,咱們能夠用 await 再處理一下 Promise。

var data = await fetch('https://www.lilnong.top/cors/A').then(v=>v.json())
var dataB = await fetch('https://www.lilnong.top/cors/B?'+new URLSearchParams(data)).then(v=>v.json())
console.log(dataB)

是否是看上去好理解多了。

課外知識

回調地獄

image.png
https://www.zhihu.com/question/49718514

async/await 地獄

這個我感受是標題黨蹭熱度吧。。
主要說下面這個例子是地獄,固然,你一看這不是就上面那個例子嗎?不就是串行執行嗎(對,有的人並行的時候也這樣寫)?

console.log(startTime = Date.now())
dataA = await fetch('/')
console.log(Date.now(), Date.now()-startTime)
dataB = await fetch('/')
console.log(Date.now(), Date.now()-startTime)

並行解決方案

console.log(startTime = Date.now())
dataA = fetch('/')
console.log(Date.now(), Date.now()-startTime)
dataB = fetch('/')
await dataA
await dataB
console.log(Date.now(), Date.now()-startTime)

課後做業

爬一篇文章 https://p.51vv.com/vp/h/hot,遇到圖片要下載,而後上傳到服務器,用服務器返回的回填,執行完成輸出文章JSON。

上面是須要實現的功能,下面來提提限制。

  1. 下載的圖片要旋轉、壓縮、轉換格式。
  2. 速度要儘量的快,可是上傳到服務器時須要串行。須要我解釋一下爲啥嗎?由於圖片有可能會有重複的。

Promise PolyFill

如何寫出一個驚豔面試官的 Promise【近 1W字】

es6-promise

微信公衆號:前端linong

clipboard.png

參考文獻

  1. 前端培訓目錄、前端培訓規劃、前端培訓計劃
  2. 使用 Promise - mdn
相關文章
相關標籤/搜索