首發於SF,未經受權,禁止各類形式轉載javascript
之前學習寫的筆記,感受還不錯,如今發出來,但願對你有幫助。文章比較長,能夠結合目錄進行閱讀,若是文章對你有所啓發和幫助,能夠『一鍵三連』。哦,對了,我已經脫髮了...😭😭java
實例對象:new
函數產生的對象, 稱爲實例對象, 簡稱爲對象程序員
函數對象: 將函數做爲對象使用時, 簡稱爲函數對象ajax
function Fn() {} const fn = new Fn() // fn爲實例對象 Fn.bind({}) // Fn爲函數對象
同步回調編程
異步回調數組
const arr = [1, 2, 3] arr.forEach(item => console.log(item)) // 同步回調, 不會放入回調隊列, 而是當即執行 console.log('forEatch()以後') setTimeout(() => { // 異步回調, 會放入回調隊列, 全部同步執行完後纔可能執行 console.log('timout 回調') }, 0) console.log('setTimeout 以後')
錯誤的類型promise
ReferenceError:引用的變量不存在異步
console.log(a) // ReferenceError: a is not defined
TypeError:數據類型不正確的錯誤async
let b = null console.log(b.xxx) // TypeError: Cannot read property 'xxx' of null
RangeError:數據值不在其所容許的範圍內異步編程
function fn() { fn() } fn() // RangeError: Maximum call stack size exceeded
SyntaxError:語法錯誤
let c = """" // SyntaxError: Unexpected string
錯誤處理
error 對象的結構
抽象表達:Promise 是JS中進行異步編程的新的解決方案(舊的是誰?=> 純回調的形式)
具體表達:
Promise的狀態改變只有這2種:
且一個 Promise 對象只能改變一次,不管變成成功仍是失敗,都會有一個結果數據,成功的結果數據通常稱爲 value
,失敗的結果數據通常稱爲 reason
。
示例,若是當前時間是偶數就表明成功,不然表明失敗
// 1. 建立一個新的Promise對象 const p = new Promise((resolve, reject) => { // 執行器函數,同步執行 // 2. 執行異步操做任務 setTimeout(() => { const time = Date.now() // 若是當前時間是偶數就表明成功,不然表明失敗 // 3.1 若是成功了,調用resolve(value) if (time % 2 === 0) { resolve('成功的數據,value = ' + time) } else { // 3.2 若是失敗了,調用reject(reason) reject('失敗的數據,reason = ' + time) } }, 1000); }) p.then(value => { // 接受獲得成功的value數據,專業術語:onResolved console.log('成功的回調', value) }, reason => { // 接受獲得失敗的reason數據,專業術語:onRejected console.log('失敗的回調', reason) })
舊的:回調函數必須在啓動異步任務前指定
// 成功的回調函數 function successCallback(result) { console.log('處理成功:' + result) } function failureCallback(error) { console.log('處理失敗:' + error) } // 使用純回調函數 createAudioFileSync(audioSettings, successCallback, failureCallback)
Promise:啓動異步任務 => 返回 Promise 對象 => 給 Promise 對象綁定回調函數,甚至能夠在異步任務結束後指定多個
// 使用 Promise const promise = createAudioFileSync(audioSettings) setTimeout(() => { promise.then(successCallback, failureCallback) }, 3000);
什麼是回調地獄?回調函數嵌套調用,外部回調函數異步執行的結果是嵌套的回掉執行條件,代碼是水平向右擴展
// 回調地獄 doSomething(function(result) { doSomethingElse(result, function(newResult) { doThirdThing(newResult, function(finalResult) { console.log('Got the final result: ' + finalResult) }, failureCallback) }, failureCallback) },
回調地獄的缺點:不便閱讀,不便於異常處理
解決方案:Promise 鏈式調用,代碼水平向下擴展
doSomething().then(function(result) { return doSomethingElse(result) }) .then(function(newResult) { return doThirdThing(newResult) }) .then(function(finalResult) { console.log('Got the final result: ' + finalResult) }) .catch(failureCallback)
終極解決方案:async/await,用同步的寫法處理異步的操做
async function request() { try { const result = await doSomething() const newResult = await doSomethingElse(result) const finalResult = await doThirdThing(newResult) console.log('Got the final result: ' + finalResult) } catch (error) { failureCallback(error) } }
Promise 構造函數。
Promise (excutor) {}
,excutor 會在 Promise 內部當即同步回調,異步操做在執行器中執行
(resolve, reject) => {}
value => {}
reason => {}
Promise.prototype.then方法
(onResolved, onRejected) => {}
,指定用於獲得成功 value 的成功回調和用於獲得失敗 reason 的失敗回調返回一個新的 promise 對象
(value) => {}
(reason) => {}
Promise.prototype.catch 方法
(onRejected) => {}
,onRejected 函數:失敗的回調函數 (reason) => {}
,then() 的語法糖, 至關於: then(undefined, onRejected)
Promise.resolve方法
(value) => {}
,value:成功的數據或 promise 對象,返回一個成功/失敗的 promise 對象
Promise.reject方法
(reason) => {}
,reason:失敗的緣由,返回一個失敗的 promise 對象
Promise.all方法
(promises) => {}
,promises:包含 n 個 promise 的數組,返回一個新的 promise, 只有全部的 promise 都成功才成功, 只要有一個失敗了就直接失敗
Promise.race方法
(promises) => {}
,promises: 包含 n 個 promise 的數組,返回一個新的 promise, 第一個完成的 promise 的結果狀態就是最終的結果狀態
// 產生一個成功值爲 1 的 Promise 對象 const p1 = new Promise((resolve, reject) => { resolve(1) }) // 產生一個成功值爲 2 的 Promise 對象 const p2 = Promise.resolve(2) // 產生一個失敗值爲 3 的 Promise 對象 const p3 = Promise.reject(3) p1.then(value => console.log(value)) p2.then(value => console.log(value)) p3.catch(reason => console.error(reason)) // const pAll = Promise.all([p1, p2]) const pAll = Promise.all([p1, p2, p3]) pAll.then(values => { console.log('all onResolved()', values) // all onResolved() [ 1, 2 ] }, reason => { console.log('all onRejected()', reason) // all onRejected() 3 }) const race = Promise.race([p1, p2, p3]) race.then(value => { console.log('all onResolved()', value) }, reason => { console.log('all onRejected()', reason) })
resolve(value),若是當前是 pendding 就會變爲 resolved
reject(reason),若是當前是 pendding 就會變爲 rejected
拋出異常,若是當前是 pendding 就會變爲 rejected
const p = new Promise((resolve, reject) => { // resolve(1) // Promise 變爲 resolved 成功狀態 // reject(2) // Promise 變爲 rejected 失敗狀態 // Promise 變爲 rejected 失敗狀態,reason爲拋出的 error throw new Error('我拋出的異常') // 變爲 rejected 失敗狀態,reason爲拋出的 3 // throw 3 }) p.then( value => {}, reason => { console.log('reason :', reason); } )
當 promise 改變爲對應狀態時都會調用
const p = new Promise((resolve, reject) => { // 變爲 rejected 失敗狀態,reason爲拋出的 3 throw 3 }) p.then( value => {}, reason => { console.log('reason :', reason); } ) p.then( value => {}, reason => { console.log('reason2 :', reason); } ) // 結果: // reason : 3 // reason2 : 3
都有可能, 正常狀況下是先指定回調再改變狀態, 但也能夠先改狀態再指定回調。
如何先改狀態再指定回調?
何時才能獲得數據?
// 常規:先指定回調函數,後改變狀態 new Promise((resolve, reject) => { setTimeout(() => { resolve(1) // 後改變狀態(同時指定數據),異步執行回調函數 }, 1000); }).then( // 先指定回調函數,保存當前指定的回調函數 value => {}, reason => { console.log('reason :', reason); } ) // 先改狀態,後指定回調函數 new Promise((resolve, reject) => { resolve(1) // 先改變狀態(同時指定數據) }).then( // 後指定回調函數,異步執行回調函數 value => { console.log('value2:', value);}, reason => { console.log('reason2 :', reason); } ) const p = new Promise((resolve, reject) => { resolve(1) // 先改變狀態(同時指定數據) }) setTimeout(() => { p.then( value => { console.log('value3:', value);}, reason => { console.log('reason3 :', reason); } ) }, 1500);
簡單表達:由 then()指定的回調函數執行的結果決定
詳細表達:
new Promise((resolve, reject) => { resolve(1) }).then( value => { console.log('onResolved1()', value); // 1 // return 1.1 或 return Promise.resolve(1.1) // return Promise.reject(1.1) // throw 1.1 }, reason => { console.log('onRejected1()', reason); } ).then( value => { console.log('onResolved2()', value); }, // 1.1 reason => { console.log('onRejected2()', reason) } // 1.1 )
promise 的 then()
返回一個新的 promise, 能夠開成 then()
的鏈式調用,經過 then 的鏈式調用串連多個同步/異步任務。
當使用 promise 的 then 鏈式調用時, 能夠在最後指定失敗的回調,前面任何操做出了異常, 都會傳到最後失敗的回調中處理。
下面的示例代碼演示了異常傳透
new Promise((resolve, reject) => { // resolve(1) reject(1) }).then( value => { console.log('onResolved1()', value); return 2 } ).then( value => { console.log('onResolved2()', value); return 3 } ).then( value => { console.log('onResolved3()', value); } ).catch( reason => { console.log('onRejected()', reason); // onRejected() 1 } )
代碼會執行 .catch
中的代碼,但實際上代碼的執行不是執行到第 3 行就直接跳轉到 catch 裏面了,而是從第一個 then 調用向下一個個的執行(逐級傳遞),可是因爲咱們 then 裏面沒有處理異常。在 then 裏面沒寫處理異常實際上至關於默認添加了 reason => { throw reason }
或者 reason => Promise.reject(reason)
:
new Promise((resolve, reject) => { reject(1) }).then( value => { console.log('onResolved1()', value); }, // reason => { throw reason } // 或者 reason => Promise.reject(reason) )
Promise的異常傳透示意圖
當使用 promise 的 then 鏈式調用時, 在中間中斷, 再也不調用後面的回調函數。
辦法: 在回調函數中返回一個 pendding
狀態的 promise 對象
new Promise((resolve, reject) => { resolve(1) }).then( value => { console.log('onResolved1()', value); return new Promise(() => {}) // 返回一個 pending 的 Promise,中斷 promise 鏈 } ).then( // 這個 then 不會執行力 value => { console.log('onResolved2()', value); } )
Async/await 實際上只是一種基於promises的糖衣語法糖,Async/await 和 promises同樣,都是非堵塞式的,Async/await 讓異步代碼更具同步代碼風格,這也是其優點所在。
async function
用來定義一個返回 AsyncFunction
對象的異步函數。異步函數是指經過事件循環異步執行的函數,它會經過一個隱式的 Promise
返回其結果,。若是你在代碼中使用了異步函數,就會發現它的語法和結構會更像是標準的同步函數。MDN async_functionawait
操做符用於等待一個Promise
對象。它只能在異步函數 async function
中使用。MDN awaitasync
函數的返回值爲 Promise
對象,async
函數返回的 Promise
的結果由函數執行的結果決定
async function fn1() { return 1 } const result = fn1() console.log(result) // Promise { 1 }
在控制檯能夠看見以下信息
既然是Promise對象,那麼咱們用 then 來調用,並拋出錯誤,執行 onRejected()
且 reason 爲錯誤信息爲「我是錯誤」
async function fn1() { // return 1 // return Promise.resolve(1) // return Promise.reject(2) throw '我是錯誤' } fn1().then( value => { console.log('onResolved()', value) }, reason => { console.log('onRejected()', reason) } // onRejected() 我是錯誤 )
await
右側的表達式通常爲 promise
對象, 但也能夠是其它的值:
promise
對象, await
返回的是 promise
成功的值await
的返回值function fn2() { return new Promise((resolve, reject) => { setTimeout(() => { resolve(1000) }, 1000); }) } function fn4() { return 6 } async function fn3() { // const value = await fn2() // await 右側表達式爲Promise,獲得的結果就是Promise成功的value // const value = await '還能夠這樣' const value = await fn4() console.log('value', value) } fn3() // value 6
await
必須寫在 async
函數中, 但 async
函數中能夠沒有 await
,若是 await
的 Promise
失敗了, 就會拋出異常, 須要經過 try...catch
捕獲處理
function fn2() { return new Promise((resolve, reject) => { setTimeout(() => { // resolve(1000) reject(1000) }, 1000); }) } async function fn3() { try { const value = await fn2() } catch (error) { console.log('獲得失敗的結果', error) } } fn3() // 獲得失敗的結果 1000
簡潔乾淨,使用async/await能省去寫多少行代碼
錯誤處理,async/wait 能用相同的結構和好用的經典 try/catch 處理同步和異步錯誤,錯誤堆棧能指出包含錯誤的函數。
調試,async/await 的一個極大優點是它更容易調試,使用async/ await則無需過多箭頭函數,而且能像正常的同步調用同樣直接跨過await調用。
~~完。
關注這個脫髮、擺攤、賣貨、持續學習的程序員,第一時間閱讀最新文章,會優先兩天發表新文章。關注便可領取大禮包,準能爲你節省很多錢!