promise

1.1 區(qū)別實例對象和函數(shù)對象

  1. 實例對象:new 函數(shù)產(chǎn)生的對象,稱為實例對象,簡稱對象;
  2. 函數(shù)對象:將函數(shù)作為對象使用時,簡稱為函數(shù)對
function Fn() {   // Fn函數(shù) 
}
const fn = new Fn() // Fn是構造函數(shù)  fn是實例對象(簡稱為對象)
console.log(Fn.prototype) // Fn是函數(shù)對象
Fn.call({}) // Fn是函數(shù)對象

// 區(qū)別函數(shù)和函數(shù)對象
// 在于函數(shù)名后加的是括號還是點,括號則是函數(shù),點則是函數(shù)對象
$('#test') // jQuery函數(shù)
$.get('/test') // jQuery函數(shù)對象

function Person(params) {

}

1.2 兩種類型的回調(diào)函數(shù)

回調(diào)函數(shù)必須滿足三個條件:1.我定義的;2.我沒調(diào)用;3.最終調(diào)用了。

1.2.1 同步回調(diào)

  1. 理解:立即執(zhí)行,完全執(zhí)行完了才結束,不會放入回調(diào)隊列中
  2. 例子:數(shù)組遍歷相關的回調(diào)函數(shù) / Promiseexcutor 函數(shù)(具體看下文)

1.2.2 異步回調(diào)

  1. 理解:不會立即執(zhí)行,會放入回調(diào)隊列中將來執(zhí)行
  2. 例子:定時器回調(diào) / ajax 回調(diào) / Promise 的成功或失敗的回調(diào)(具體看下文)
如何區(qū)分同步回調(diào)和異步回調(diào)?

在回調(diào)函數(shù)之后打印輸出內(nèi)容;

如果內(nèi)容在回調(diào)函數(shù)執(zhí)行之后輸出,則是同步回調(diào);反之則是異步回調(diào)。

// 1\. 同步回調(diào)函數(shù)
// const arr = [1, 3, 5]
arr.forEach(item => { // 遍歷回調(diào), 同步回調(diào)函數(shù), 不會放入列隊, 一上來就要執(zhí)行完
  console.log(item)
})
console.log('forEach()之后')

// 2\. 異步回調(diào)函數(shù)
setTimeout(() => { // 異步回調(diào)函數(shù), 會放入隊列中將來執(zhí)行
  console.log('timout callback()')
}, 0)
console.log('setTimeout()之后')

1.3 JSerror 處理

1.3.1 錯誤的類型

  1. Error:所有錯誤的父類型
  2. ReferenceError:引用的變量不存在;如:未聲明之下打印一個變量: console.log(a)
  3. TypeError:數(shù)據(jù)類型不正確的錯誤,如:把一個普通變量當對象用:let b; console.log(b.xxx)
  4. RangeError:數(shù)據(jù)值不在其所允許的范圍內(nèi),如:遞歸溢棧
  5. SyntaxError:語法錯誤,如:console.log("""")

1.3.2 錯誤處理

  1. 捕獲處理錯誤:try...catch
  2. 拋出錯誤:throw error;由調(diào)用者決定如何處理錯誤,后面可以捕獲再處理

1.3.3 error 對象的結構

error 對象有兩個屬性:messagestact

message 屬性:錯誤相關信息

stack 屬性:函數(shù)調(diào)用棧記錄信息(可打斷點查看)

/* 
目標: 進一步理解JS中的錯誤(Error)和錯誤處理
  mdn文檔: https: //developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Error

  1\. 錯誤的類型
      Error: 所有錯誤的父類型
      ReferenceError: 引用的變量不存在
      TypeError: 數(shù)據(jù)類型不正確的錯誤
      RangeError: 數(shù)據(jù)值不在其所允許的范圍內(nèi)
      SyntaxError: 語法錯誤
  2\. 錯誤處理
      捕獲錯誤: try ... catch
      拋出錯誤: throw error
  3\. 錯誤對象
      message屬性: 錯誤相關信息
      stack屬性: 函數(shù)調(diào)用棧記錄信息
*/

// 1\. 常見的內(nèi)置錯誤
// 1). ReferenceError: 引用的變量不存在
// console.log(a) // ReferenceError: a is not defined
// console.log('-----') // 沒有捕獲error, 下面的代碼不會執(zhí)行

// TypeError: 數(shù)據(jù)類型不正確的錯誤
// let b
// // console.log(b.xxx) // TypeError: Cannot read property 'xxx' of undefined
// b = {}
// b.xxx() // TypeError: b.xxx is not a function

// RangeError: 數(shù)據(jù)值不在其所允許的范圍內(nèi)
// function fn() {
//   fn()
// }
// fn() // RangeError: Maximum call stack size exceeded

// SyntaxError: 語法錯誤
// const c = """" // SyntaxError: Unexpected string

// 2\. 錯誤處理
// 捕獲錯誤: try ... catch
// try {
//   let d
//   console.log(d.xxx)
// } catch (error) {
//   console.log(error.message)
//   console.log(error.stack)
// }
// console.log('出錯之后')

// 拋出錯誤: throw error
function something() {
  if (Date.now()%2===1) {
    console.log('當前時間為奇數(shù), 可以執(zhí)行任務')
  } else { // 如果時間是偶數(shù)拋出異常, 由調(diào)用來處理
    throw new Error('當前時間為偶數(shù)無法執(zhí)行任務')  
  }
}

// 捕獲處理異常
try {
  something()
} catch (error) {
  alert(error.message)
}

第2章:promise 的理解和使用

2.1 Promise 是什么?

2.1.1 理解

  1. 抽象表達

    PromiseJS進行異步編程解決方案

  2. 具體表達

    (1)從語法上來說:Promise 是一個構造函數(shù)

    (2)從功能上來說:promise 對象用來封裝一個異步操作并可以獲取其結果

2.1.2 promise 狀態(tài)改變

promise 對象只能有三種狀態(tài),pending、resolved、rejected,而狀態(tài)改變只有以下兩種情況。

  1. pending 變?yōu)?resolved
  2. pending 變?yōu)?rejected

說明

狀態(tài)改變只有這兩種,而且一個 promise 對象只能改變一次

無論變?yōu)槌晒蛘呤?,都會有一個最終結果;成功的結果數(shù)據(jù)一般稱為 value,失敗的結果數(shù)據(jù)一般稱為 reason

2.1.3 promise 的基本流程

image

2.1.4 promise 的基本使用

// 1\. 創(chuàng)建一個新的promise對象
const p = new Promise((resolve, reject) => {// 執(zhí)行器函數(shù)  同步回調(diào)
  console.log('執(zhí)行 excutor')
  // 2\. 執(zhí)行異步操作任務
  setTimeout(() => {
    const time = Date.now() // 如果當前時間是偶數(shù)就代表成功, 否則代表失敗
    // 3.1\. 如果成功了, 調(diào)用resolve(value)
    if (time %2 == 0) {
      resolve('成功的數(shù)據(jù), time=' + time)
    } else {
    // 3.2\. 如果失敗了, 調(diào)用reject(reason)
      reject('失敗的數(shù)據(jù), time=' + time)
    }
  }, 1000);

})
console.log('new Promise()之后')

// setTimeout(() => {
  p.then(
  value => { // 接收得到成功的value數(shù)據(jù)    onResolved
    console.log('成功的回調(diào)', value)  
  },
  reason => {// 接收得到失敗的reason數(shù)據(jù)  onRejected
    console.log('失敗的回調(diào)', reason)
  }
// )
// }, 2000);

2.2 為什么要用 promise ?

2.2.1 指定回調(diào)函數(shù)的方式更加靈活

  1. 舊的(純回調(diào)函數(shù)):必須在啟動異步任務之前指定

  2. promise:啟動異步任務 => 返回 promise 對象 => 給 promise 對象綁定回調(diào)函數(shù)(甚至可以在異步任務結束后指定【可加定時器】/多個)

    (一般情況下異步任務執(zhí)行需要時間嘛,那么就會先執(zhí)行下面的代碼,會調(diào)用 then() 方法,從而綁定回調(diào)函數(shù))

2.2.2 支持鏈式調(diào)用,可以解決回調(diào)地獄問題

  1. 什么是回調(diào)地獄?

    回調(diào)函數(shù)嵌套調(diào)用,外部回調(diào)函數(shù)異步執(zhí)行的結果是嵌套的回調(diào)執(zhí)行的條件

    (回調(diào)函數(shù)層層嵌套,外面的回調(diào)函數(shù)執(zhí)行完了,才會把結果傳給里面的回調(diào)函數(shù),作為條件

  2. 回調(diào)地獄的缺點?

    不便于閱讀

    不便于異常處理

  3. 解決方案?

    promise 鏈式調(diào)用

  4. 最終解決方案?

    async/await

  // 成功的回調(diào)函數(shù)
  function successCallback(result) {
    console.log("聲音文件創(chuàng)建成功: " + result);
  }
  // 失敗的回調(diào)函數(shù)
  function failureCallback(error) {
    console.log("聲音文件創(chuàng)建失敗: " + error);
  }

  /* 1.1 使用純回調(diào)函數(shù) */
  createAudioFileAsync(audioSettings, successCallback, failureCallback)

/* 1.2\. 使用Promise */
  const promise = createAudioFileAsync(audioSettings); // 2
  setTimeout(() => {
    promise.then(successCallback, failureCallback);
  }, 3000);

  /* 
  2.1\. 回調(diào)地獄
  */
  doSomething(function(result) {
    doSomethingElse(result, function(newResult) {
      doThirdThing(newResult, function(finalResult) {
        console.log('Got the final result: ' + finalResult)
      }, failureCallback)
    }, failureCallback)
  }, failureCallback)

  /* 
  2.2\. 使用promise的鏈式調(diào)用解決回調(diào)地獄
  */
  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)

  /* 
  2.3\. async/await: 回調(diào)地獄的終極解決方案
  */
  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)
    }
  }

2.3 如何使用 promise ?

2.3.1 API

  1. Promise 構造函數(shù): Promise (excutor) {}

    excutor 函數(shù):同步執(zhí)行 (resolve, reject) => {}

    resolve 函數(shù):內(nèi)部定義成功時我們調(diào)用的函數(shù) value => {}

    reject 函數(shù):內(nèi)部定義失敗時我們調(diào)用的函數(shù) reason => {}

  2. Promise.prototype.then 方法:(onResolved, onRejected) => {}

    onResolved 函數(shù):成功的回調(diào)函數(shù) (value) => {}

    onRejected 函數(shù):失敗的回調(diào)函數(shù) (reason) => {}

    說明:指定用于得到成功 value 的成功回調(diào)和用于得到失敗 reason 的失敗回調(diào),返回一個新的 promise 對象

  3. Promise.prototype.catch 方法:(onRejected) => {}

    onRejected 函數(shù):失敗的回調(diào)函數(shù) (reason) => {}

    說明: then() 的語法糖,相當于:then(undefined, onRejected)

  4. Promise.resolve 方法:(value) => {}

    value:成功的數(shù)據(jù)或 promise 對象

    說明:返回一個成功/失敗的 promise 對象

  5. Promise.reject 方法:(reason) => {}

    reason:失敗的原因

    說明:返回一個失敗的 promise 對象

  6. Promise.all 方法:(promises) => {}

    promises:包含 npromise 的數(shù)組

    說明:返回一個新的 promise,只有所有的 promise 都成功才成功,只要有一個失敗了就直接失敗

  7. Promise.race 方法:(promises) => {}

    promise:包含 npromise 的數(shù)組

    說明:返回一個新的 promise,第一個完成的 promise 的結果狀態(tài)就是最終的結果狀態(tài)

new Promise((resolve, reject) => {
setTimeout(() => {
    // resolve('成功的數(shù)據(jù)')
    reject('失敗的數(shù)據(jù)')
}, 1000)
}).then(
value => {
    console.log('onResolved()1', value)
}
).catch(
reason => {
    console.log('onRejected()1', reason)
}
)

// 產(chǎn)生一個成功值為1的promise對象
const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
    resolve(1)
    }, 100);
})
const p2 = Promise.resolve(2)
const p3 = Promise.reject(3)
//    p1.then(value => {console.log(value)})
//    p2.then(value => {console.log(value)})
//    p3.catch(reason => {console.log(reason)})

//    const pAll = Promise.all([p1, p2, p3])
const pAll = Promise.all([p1, p2])
/* pAll.then(
  values => {
    console.log('all onResolved()', values)
  },
  reason => {
    console.log('all onRejected()', reason)
  }
)
*/
const pRace = Promise.race([p1, p2, p3])
pRace.then(
  value => {
    console.log('race onResolved()', value)
  },
  reason => {
    console.log('race onRejected()', reason)
  }
)

2.3.2 promise 的幾個關鍵問題

  1. 如何改變 promise 的狀態(tài)?

    (1)resolve(value):如果當前是 pending 就會變?yōu)?resolved

    (2)reject(reason):如果當前是 pending 就會變?yōu)?rejected

    (3)拋出異常:如果當前是 pending 就會變?yōu)?rejected

  2. 一個 promise 指定多個成功/失敗回調(diào)函數(shù),都會調(diào)用嗎?

    promise 改變?yōu)閷獱顟B(tài)時都會調(diào)用

  3. 改變 promise 狀態(tài)和指定回調(diào)函數(shù)誰先誰后?

    (1)都有可能,正常情況下是先指定回調(diào)再改變狀態(tài),但也可以先改變狀態(tài)再指定回調(diào)

    (2)如何先改狀態(tài)再指定回調(diào)?

    • 在執(zhí)行器中直接調(diào)用 resolve()/reject()
    • 延遲更長時間才調(diào)用 then()

    (3)什么時候才能得到數(shù)據(jù)?

    關鍵在于回調(diào)函數(shù)調(diào)用時,才能得到數(shù)據(jù)

    • 如果先指定的回調(diào),那當狀態(tài)發(fā)生改變時,回調(diào)函數(shù)就會調(diào)用,得到數(shù)據(jù)

    • 如果先改變的狀態(tài),那當指定回調(diào)時,回調(diào)函數(shù)就會調(diào)用,得到數(shù)據(jù)

  4. promise.then() 返回的新 promise 的結果狀態(tài)由什么決定?

    (1)簡單表達:由 then() 指定的回調(diào)函數(shù)執(zhí)行的結果決定

    (2)詳細表達:

    • 如果拋出異常,新 promise 變?yōu)?rejectedreason 為拋出的異常

    • 如果返回的是非 promise 的任意值,新 promise 變?yōu)?resolved,value 為返回的值

    • 如果返回的是另一個新 promise,那么返回的 promise 的結果就會成為新(原來的) promise 結果

  5. promise 如何串連多個操作任務?

    (1)promisethen() 返回一個新的 promise,可以看成 then() 的鏈式調(diào)用

    (2)通過 then 的鏈式調(diào)用串連多個同步/異步任務

  6. promise 異常傳/穿透?

    (1)當使用 promisethen 鏈式調(diào)用時,可以在最后指定失敗的回調(diào)

    (2)前面任何操作出了異常,都會傳到最后失敗的回調(diào)中處理

  7. 中斷 promise 鏈?

    (1)當使用 promisethen 鏈式調(diào)用時,在中間中斷,不再調(diào)用后面的回調(diào)函數(shù)

    (2)方法:在回調(diào)函數(shù)中返回一個狀態(tài)為 pendingpromise 對象

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容