細(xì)讀 ES6 | Promise 上篇

配圖源自 Freepik

我認(rèn)為 Promise 應(yīng)該算是 ES6 標(biāo)準(zhǔn)最大的亮點(diǎn),它提供了異步編程的一種解決方案。比傳統(tǒng)的回調(diào)函數(shù)和事件解決方案,它更合理、更強(qiáng)大。

一、簡(jiǎn)介

Promise 是一個(gè)容器,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(一般為異步操作)的結(jié)果。從語(yǔ)法上來(lái)說(shuō),Promise 是一個(gè)對(duì)象,它可以獲取異步操作的消息。

Promise 對(duì)象的特點(diǎn):

  • Promise 對(duì)象有且只有三種狀態(tài):pendingfulfilled、rejected,分別表示進(jìn)行中、已成功、已失敗。

  • 一旦狀態(tài)發(fā)生改變,就不會(huì)再變。狀態(tài)的改變只有兩種可能:pending -> fulfilledpending -> rejected。若發(fā)生了其中一種情況,狀態(tài)就會(huì)一直保存這個(gè)結(jié)果,這時(shí)就成為 resolved(已定型)。

這種以“同步的方式”去表達(dá)異步流程,可以避免層層嵌套的回調(diào)函數(shù),避免出現(xiàn)“回調(diào)地獄”(Callback Hell)。

BTW,網(wǎng)上有些文章把 fulfilled 狀態(tài),叫成 resolved,盡管我們可能知道他想表達(dá)的意思,但其實(shí)是不對(duì)的。

Promise 對(duì)象的缺點(diǎn):

一是無(wú)法取消 Promise,一旦創(chuàng)建它就會(huì)立即執(zhí)行,無(wú)法中途取消;二是若不設(shè)置回調(diào)函數(shù)情況下,Promise 內(nèi)部拋出錯(cuò)誤,不會(huì)反饋到外部;三是當(dāng)處于 pending 狀態(tài),無(wú)法得知目前進(jìn)展到哪個(gè)階段。

二、Promise 用法

根據(jù)規(guī)定,Promise 是一個(gè)構(gòu)造函數(shù),用來(lái)生成 Promise 實(shí)例對(duì)象。

1. 創(chuàng)建 Promise 對(duì)象

示例:

const handler = (resolve, reject) => {
  // some statements...

  // 根據(jù)異步操作的結(jié)果,通過(guò) resolve 或 reject 函數(shù)去改變 Promise 對(duì)象的狀態(tài)
  if (true) {
    // pending -> fulfilled
    resolve(...)
  } else {
    // pending -> rejected
    reject(...)
  }

  // 需要注意的是:
  // 1. 在上面 Promise 狀態(tài)已經(jīng)定型(fulfilled 或 rejected),
  //    因此,我們?cè)偈褂?resolve() 或 reject() 或主動(dòng)/被動(dòng)拋出錯(cuò)誤的方式,
  //    試圖再次修改狀態(tài),是沒(méi)用的,狀態(tài)不會(huì)再發(fā)生改變。
  // 2. 當(dāng) Promise 對(duì)象的狀態(tài)“已定型”后,若未使用 return 終止代碼往下執(zhí)行,
  //    后面代碼出現(xiàn)的錯(cuò)誤(主動(dòng)拋出或語(yǔ)法錯(cuò)誤等),在外部都不可見,無(wú)法捕獲到。
  // 3. hander 函數(shù)的返回值是沒(méi)意義的。怎么理解?
  //    假設(shè)內(nèi)部不包括 resolve() 或 reject() 或內(nèi)部不出現(xiàn)語(yǔ)法錯(cuò)誤,
  //    或不主動(dòng)拋出錯(cuò)誤,僅有類似 `return 'anything'` 語(yǔ)句,
  //    那么 promise 對(duì)象永遠(yuǎn)都是 pending 狀態(tài)。
}

const promise = new Promise(handler)

Promie 構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù),該函數(shù)的兩個(gè)參數(shù)分別是 resolvereject。而 resolverejeact 也是函數(shù),其作用是改變 Promise 對(duì)象的狀態(tài),分別是 pending -> fulfilledpending -> rejected。

假設(shè)構(gòu)造函數(shù)內(nèi)不指定 resolvereject 函數(shù),那么 Promise 的對(duì)象會(huì)一直保持著 pending 待定的狀態(tài)。

2. Promise 實(shí)例

Promise 實(shí)例生成以后,當(dāng) Promise 內(nèi)部狀態(tài)發(fā)生變化,可以使用 Promise.prototype.then() 方法獲取到。

const success = res => {
  // 當(dāng)狀態(tài)從 pending 到 fulfilled 時(shí),執(zhí)行此函數(shù)
  // some statements...
}

const fail = err => {
  // 當(dāng)狀態(tài)從 pending 到 rejected 時(shí),執(zhí)行此函數(shù)
  // some statements...
}

promise.then(success, fail)

then() 方法接受兩個(gè)回調(diào)函數(shù)作為參數(shù),第一個(gè)回調(diào)函數(shù)在 Promise 對(duì)象狀態(tài)變?yōu)?fulfilled 時(shí)被調(diào)用。第二回調(diào)函數(shù)在狀態(tài)變?yōu)?rejected 時(shí)被調(diào)用。then() 方法的兩個(gè)參數(shù)都是可選的。

注意,由于 Promise 實(shí)例對(duì)象的 Promise.prototype.then()、Promise.prototype.catch()Promise.prototype.finally() 方法屬于異步任務(wù)中的微任務(wù)。注意它們的執(zhí)行時(shí)機(jī),會(huì)在當(dāng)前同步任務(wù)執(zhí)行完之后,且在下一次宏任務(wù)執(zhí)行之前,被執(zhí)行。

還有,Promise 構(gòu)造函數(shù)(即上述示例的 handler 函數(shù))內(nèi)部,仍屬于同步任務(wù),而非異步任務(wù)。

所以,那個(gè)經(jīng)典的面試題就是,包括 setTimeout、Promise 等,然后問(wèn)輸出順序是什么?本質(zhì)就是考察 JavaScript 的事件循環(huán)機(jī)制(Event Loop)嘛。這塊內(nèi)容可以看下文章:JavaScript 事件循環(huán)。

插了個(gè)話題,回來(lái)

then() 方法的兩個(gè)參數(shù) success()、fail(),它們接收的實(shí)參就是傳遞給 resolve()reject() 的值。

例如:

function timeout(delay, status = true) {
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      // 一般 reject 應(yīng)返回一個(gè) Error 實(shí)例對(duì)象,如:new Error('Oops')
      status ? resolve('Success') : reject('Oops')
    })
  }, delay)
  return promise
}

// 創(chuàng)建兩個(gè) Promise 實(shí)例對(duì)象
const p1 = timeout(1000)
const p2 = timeout(1000, false)

// pending -> fulfilled
p1.then(res => {
  console.log(res) // "Success"
})

// pending -> rejected
p2.then(null, err => {
  console.warn(err) // "Oops"
})

上面示例中,根據(jù) timeout 函數(shù)的邏輯,p1 實(shí)例的 Promise 狀態(tài)會(huì)從 pending -> fulfilled,而 p2 實(shí)例則是從 pending -> rejected。因此會(huì)分別打印出 "Success"、"Oops"。

例如,異步加載圖片的例子。

function loadImage(url) {
  return new Promise((resolve, reject) => {
    const image = new Image()
    image.onload = function () {
      resolve(image)
    }
    image.onerror = function () {
      reject(new Error(`Could not load image at ${url}.`))
    }
    image.src = url
  })
}

loadImage('https://jquery.com/jquery-wp-content/themes/jquery/images/logo-jquery@2x.png')
  .then(
    res => {
      console.log('Image loaded successfully:', res)
    },
    err => {
      console.warn(err)
    }
  )

因此,Promise 的用法還是很簡(jiǎn)單的,是預(yù)期結(jié)果的話,使用 resolve() 修改狀態(tài)為 fulfilled,非預(yù)期結(jié)果使用 reject() 修改狀態(tài)為 rejected。具體返回值根據(jù)實(shí)際場(chǎng)景返回就好。

3. Promise 注意事項(xiàng)

在構(gòu)建 Promise 對(duì)象的內(nèi)部,使用 resolve()reject() 去改變 Promise 的狀態(tài),并不會(huì)終止 resolvereject 后面代碼的執(zhí)行。

例如:

const promise = new Promise((resolve, reject) => {
  resolve(1)
  // 以下代碼仍會(huì)執(zhí)行,且會(huì)在 then 之前執(zhí)行。
  // reject() 同理。
  console.log(2)
})

promise.then(res => { console.log(res) }) // 先后打印出 2、1

若要終止后面的執(zhí)行,只要使用 return 關(guān)鍵字即可,類似 return resolve(1)return reject(1)。但如果這樣,其實(shí)后面的代碼就沒(méi)意義,因此也就沒(méi)必要寫了。千萬(wàn)別在工作中寫出這樣的代碼,我怕你被打。這里只是為了說(shuō)明 resolvereject 不會(huì)終止后面的代碼執(zhí)行而已。

一般來(lái)說(shuō),調(diào)用 resolve()reject() 說(shuō)明異步操作有了結(jié)果,那么 Promise 的使命就完成了,后續(xù)的操作應(yīng)該是放到 then() 方法里面,而不是放在 resolve()reject() 后面。

在前面的示例中,resolve()reject() 都是返回一個(gè)“普通值”。如果我們返回一個(gè) Promise 對(duì)象,會(huì)怎樣呢?

首先,它是允許返回一個(gè) Promise 對(duì)象的,但是有些區(qū)別。

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p1 success')
    // reject('p1 fail')
  }, 3000)
})

const p2 = new Promise((resolve, reject) => {
  // 這時(shí)返回一個(gè) Promise 對(duì)象
  // ?? 注意,這里 resolve(p1) 或 reject(p1) 執(zhí)行的邏輯會(huì)有所不同。
  resolve(p1)
  // reject(p1)
})

p2.then(
  res => {
    console.log('p2 then:', res)
  },
  err => {
    console.log('p2 catch:', err)
  }
)

分析如下:

1. 若 p2 內(nèi)里面 `resolve(p1)` 時(shí):

   當(dāng)代碼執(zhí)行到 `resolve(p1)` 時(shí),由于 p1 的狀態(tài)仍是 pending,
   這時(shí) p1 的狀態(tài)會(huì)傳遞給 p2,也就是說(shuō) p1 的狀態(tài)決定了 p2 的狀態(tài),
   因此 `p2.then()` 需要等 p1 的狀態(tài)發(fā)生變化,才會(huì)被調(diào)用,
   且 `p2.then()` 獲取到的狀態(tài)就是 p1 的狀態(tài)

   假設(shè)代碼執(zhí)行到 `resolve(p1)` 時(shí),若 p1 的狀態(tài)已定型,即 fulfilled 或 rejected,
   會(huì)立即調(diào)用 `p2.then()` 方法。
   PS:這里“立即”是指,當(dāng)前同步任務(wù)已執(zhí)行完畢的前提下。第 2 點(diǎn)也是如此。
  
2. 若 p2 內(nèi)是 `reject(p1)` 時(shí),情況會(huì)有所不同:

   當(dāng)代碼執(zhí)行到 `reject(p1)` 時(shí),由于 p2 的狀態(tài)會(huì)變更為 rejected,
   接著會(huì)立即調(diào)用 `p2.then()` 方法,由于是 rejected 狀態(tài),
   因此,會(huì)觸發(fā) `p2.then()` 的第二個(gè)參數(shù),此時(shí) err 的值就是 p1(一個(gè) Promise 對(duì)象)。

   假設(shè) p1 的狀態(tài)最終變成了 rejected,那么 err 還要捕獲異常,
   例如 `err.catch(err => { /* do something... */ })`,
   否則的話,在控制臺(tái)會(huì)報(bào)錯(cuò),類似:"Uncaught (in promise) p1 fail",
   原因就是 Promise 對(duì)象的 rejected 狀態(tài)未處理,導(dǎo)致的。

   假設(shè) p1 的狀態(tài)最終變成 fulfilled,那么不需要做上一步類似的處理。

上面兩種情況,其實(shí)相當(dāng)于 Promise.resolve(p1)、Promise.reject(p1)。我們來(lái)打印一下兩種結(jié)果:

當(dāng) p1 狀態(tài)為 fulfilled 時(shí),p2 狀態(tài)如圖:

當(dāng) p1 狀態(tài)為 rejected 時(shí),p2 狀態(tài)如圖:

三、Promise.prototype.then()

Promise 的實(shí)例具有 then() 方法,它是定義在原型對(duì)象 Promise.prototype 上的。當(dāng) Promise 實(shí)例對(duì)象的狀態(tài)發(fā)生變化,此方法就會(huì)被觸發(fā)調(diào)用。

前面提到 Promise.prototype.then() 接受兩個(gè)參數(shù),兩者均可選,這里不再贅述。

then() 方法返回一個(gè)新的 Promise 實(shí)例對(duì)象(注意,不是原來(lái)那個(gè) Promise 實(shí)例),也因此可以采用鏈?zhǔn)綄懛?,?then() 方法后面可以再調(diào)用另一個(gè) then() 方法。

例如,以下示例使用 Fetch API 進(jìn)行網(wǎng)絡(luò)請(qǐng)求:

window.fetch('/config')
  .then(response => response.json())
  .then(
    res => {
      // do something...
    },
    err => {
      // do something...
    }
  )
  // .then() // ...

以上鏈?zhǔn)秸{(diào)用,會(huì)按照順序調(diào)用回調(diào)函數(shù),后一個(gè) then() 的執(zhí)行,需等到前一個(gè) Promise 對(duì)象的狀態(tài)定型。

四、Promise.prototype.catch()

Promise.prototype.catch() 方法是 then(null, rejection)then(undefined, rejection) 的別名,用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù)。

同樣地,它會(huì)返回一個(gè)新的 Promise 實(shí)例對(duì)象。

const promise = new Promise((resolve, reject) => {
  reject('Oops') // 或通過(guò) throw 方式主動(dòng)拋出錯(cuò)誤,使其變成 rejected 狀態(tài)
  // 但注意的是,前面狀態(tài)“定型”之后,狀態(tài)是不會(huì)再變的。
  // 這后面試圖改變狀態(tài),或主動(dòng)拋出錯(cuò)誤,或出現(xiàn)其他語(yǔ)法錯(cuò)誤,
  // 不會(huì)被外部捕獲到,即無(wú)意義。
})

promise.catch(err => {
  console.log(err) // "Oops"
})

// 相當(dāng)于
promise.then(
  null,
  err => {
    console.log(err) // "Oops"
  }
)

通過(guò) throw 等方式使其變成 rejected 狀態(tài),相當(dāng)于:

const promise = new Promise((resolve, reject) => {
  try {
    throw 'Oops' 
    // 一般地,是拋出一個(gè) Error(或派生)實(shí)例對(duì)象,如 throw new Error('Oops')
  } catch (e) {
    reject(e)
  }
})

五、捕獲 rejected 狀態(tài)的兩種方式比較

前面提到有兩種方式,可以捕獲 Promise 對(duì)象的 rejected 狀態(tài)。那么孰優(yōu)孰劣呢?

建議如下:

盡量不要在 Promise.prototype.then() 方法里面定義 onRejection 回調(diào)函數(shù)(即 then() 的第二個(gè)參數(shù)),總使用 Promise.prototype.catch() 方法。

const promise = new Promise((resolve, reject) => {
  // some statements
})

// bad
promise.then(
  res => { /* some statements */ },
  err => { /* some statements */ }
)

// good
promise
  .then(res => { /* some statements */ })
  .catch(err => { /* some statements */ })

上面示例中,第二種寫法要好于第一種寫法。理由是第二種寫法可以捕獲前面 then() 方法中的異?;蝈e(cuò)誤,也更接近同步寫法(try...catch)。因此,建議總是使用 Promise.prototype.catch() 方法。

與傳統(tǒng)的 try...catch 代碼塊不同的是,即使 Promise 內(nèi)部出現(xiàn)錯(cuò)誤,也不會(huì)影響 Promise 外部代碼的執(zhí)行。

const promise = new Promise((resolve, reject) => {
  say() // 這行會(huì)報(bào)錯(cuò):ReferenceError: say is not defined
})

promise.then(res => { /* some statements */ })

setTimeout(() => {
  console.log(promise) // 這里仍會(huì)執(zhí)行,打印出 promise 實(shí)例對(duì)象
})

上面的示例中,在 Promise 內(nèi)部就會(huì)發(fā)生引用錯(cuò)誤,因?yàn)?say 函數(shù)并沒(méi)有定義,但并未終止腳本的執(zhí)行。接著還會(huì)輸出 promise 對(duì)象。也就是說(shuō),Promise 內(nèi)部的錯(cuò)誤并不會(huì)影響到 Promise 外部代碼,通俗的說(shuō)法就是“Promise 會(huì)吃掉錯(cuò)誤”。

但是,如果腳本放在服務(wù)器上執(zhí)行,退出碼就是 0(表示執(zhí)行成功)。不過(guò) Node.js 有一個(gè) unhandledRejection 事件,它專門監(jiān)聽未捕獲的 reject 錯(cuò)誤,腳本會(huì)觸發(fā)這個(gè)事件的監(jiān)聽函數(shù),可以在監(jiān)聽函數(shù)里面拋出錯(cuò)誤。如下:

注意,Node.js 有計(jì)劃在未來(lái)廢除 unhandledRejection 事件。如果 Promise 內(nèi)部由未捕獲的錯(cuò)誤,會(huì)直接終止進(jìn)程,并且進(jìn)程的退出碼不為 0。

catch() 方法中,也可以拋出錯(cuò)誤。而且由于 then()catch() 方法均返回一個(gè)新的 Promise 實(shí)例對(duì)象,因此可以采用鏈?zhǔn)綄懛?,寫出一系列?..

const promise = new Promise((resolve, reject) => {
  reject('Oops')
})

promise
  .then(res => { /* some statements */ })
  .catch(err => { throw new Error('Oh...') })
  .catch(err => { /* 這里可以捕獲上一個(gè) rejected 狀態(tài) */ })
  // ... 還可以寫一系列的 then、catch 方法

六、Promise.prototype.finally()

在 ES9 標(biāo)準(zhǔn)中,引入了 Promise.prototype.finally() 方法,用于指定 Promise 對(duì)象狀態(tài)發(fā)生改變(不管 fulfilled 還是 rejected)后,都會(huì)觸發(fā)此方法。

const promise = new Promise((resolve, reject) => {
  // some statements
})

promise
  .then(res => { /* some statements */ })
  .catch(err => { /* some statements */ })
  .finally(() => {
    // do something...
    // 注意,finally 不接受任何參數(shù),自然也無(wú)法得知 Promise 對(duì)象的狀態(tài)。
  })

若 Promise 內(nèi)部不寫任何 resovle()、或 rejected()、或無(wú)任何語(yǔ)法錯(cuò)誤(如上述示例),Promise 實(shí)例對(duì)象的狀態(tài)并不會(huì)發(fā)生變化,即一直都是 pending 狀態(tài),它都不會(huì)觸發(fā) then()、catch()finally() 方法。這點(diǎn)就怕有人會(huì)誤解,狀態(tài)不發(fā)生變化時(shí)也會(huì)觸發(fā) finally() 方法,這是錯(cuò)的。

Promise.prototype.finally() 也是返回一個(gè)新的 Promise 實(shí)例對(duì)象,而且該實(shí)例對(duì)象的值,就是前面一個(gè) Promise 實(shí)例對(duì)象的值。

const p1 = new Promise(resolve => resolve(1))
const p2 = p1.then().finally()
const p3 = p1.then(() => { }).finally()
const p4 = p1.then(() => { return true }).finally()
const p5 = p1.then(() => { throw 'Oops' /* 當(dāng)然這里沒(méi)處理 rejected 狀態(tài) */ }).finally()
const p6 = p1.then(() => { throw 'Oh...' }).catch(err => { return 'abc' }).finally()
const p7 = p1.finally(() => { return 'finally' })
const p8 = p1.finally(() => { throw 'error' })

setTimeout(() => {
  console.log('p1:', p1)
  console.log('p2:', p2)
  console.log('p3:', p3)
  console.log('p4:', p4)
  console.log('p5:', p5)
  console.log('p6:', p6)
  console.log('p7:', p7)
  console.log('p8:', p8)
})

// 解釋一下 `p1` 和 `p1.then()`:
// 當(dāng) `then()` 方法中不寫回調(diào)函數(shù)時(shí),會(huì)發(fā)生值的穿透,
// 即 `p1.then()` 返回的新實(shí)例對(duì)象(假設(shè)為 `x`)的值跟 p1 實(shí)例的值是一樣的,
// 但注意 `p1` 和 `x` 是兩個(gè)不同的 Promise 實(shí)例對(duì)象。
// 關(guān)于值穿透的問(wèn)題,后面會(huì)給出示例。

根據(jù)打印結(jié)果可以驗(yàn)證: finally() 方法返回的 Promise 實(shí)例對(duì)象的值與前一個(gè) Promise 實(shí)例對(duì)象的值是相等的,但盡管如此,兩者是兩個(gè)不同的 Promise 實(shí)例對(duì)象??梢源蛴∫幌?p1 === p7,比較結(jié)果為 false

關(guān)于 Promise.prototype.finally() 的實(shí)現(xiàn),如下:

Promise.prototype.finally = function (callback) {
  let P = this.constructor
  return this.then(
    value => P.resolve(callback && callback()).then(() => value),
    reason => P.resolve(callback && callback()).then(() => { throw reason })
  )
}

七、總結(jié)

關(guān)于 Promise.prototype.then()、Promise.prototype.catch()、Promise.prototype.finally() 方法,總結(jié)以下特點(diǎn):

  • 三者均返回一個(gè)全新的 Promise 實(shí)例對(duì)象。

  • 即使 then()、catch()、finally() 方法在不指定回調(diào)函數(shù)的情況下,仍會(huì)返回一個(gè)全新的 Promise 實(shí)例對(duì)象,但此時(shí)會(huì)出現(xiàn)“值穿透”的情況,即實(shí)例值為前一個(gè)實(shí)例的值。

  • 假設(shè)三者的回調(diào)函數(shù)中無(wú)語(yǔ)法錯(cuò)誤(包括不使用 throw 關(guān)鍵字) 時(shí),then()catch() 方法返回的實(shí)例對(duì)象的值,依靠 return 關(guān)鍵字來(lái)指定,否則為 undefined。

    finally() 方法稍有不同,即使使用了 return 也是無(wú)意義的,因?yàn)樗祷氐?Promise 實(shí)例對(duì)象的值總是前一個(gè) Promise 實(shí)例的值。

    三個(gè)方法的返回操作 return any,相當(dāng)于 Promise.resolve(any)(這里 any 是指任何值)。

  • 當(dāng) then()、catch()finally() 方法中出現(xiàn)語(yǔ)法錯(cuò)誤或者利用 throw 關(guān)鍵字主動(dòng)拋出錯(cuò)誤,它們返回的 Promise 實(shí)例對(duì)象的狀態(tài)會(huì)變成 rejected,而且實(shí)例對(duì)象的值就是所拋出的錯(cuò)誤原因。

  • Promise 對(duì)象的錯(cuò)誤具有“冒泡”性質(zhì),會(huì)一直向后傳遞,直到被捕獲為止。也就是說(shuō),錯(cuò)誤總是會(huì)被下一個(gè) catch() 方法捕獲。

關(guān)于值的“穿透”,請(qǐng)看示例:

const person = { name: 'Frankie' } // 使用引用值更能說(shuō)明問(wèn)題
const p1 = new Promise(resolve => resolve(person))
const p2 = new Promise((resolve, reject) => reject(person))

// 情況一:fulfilled
p1.then(res => {
  console.log(res === person) // true
})

// 情況二:fulfilled
p1
  .then()
  .then(res => {
    console.log(res === person) // true
  })

// 情況三:rejected
p2
  .catch()
  .then(res => { /* 不會(huì)觸發(fā) then */ })
  .catch(err => {
    console.log(err === person) // true
  })

// 情況四:fulfilled
p1
  .finally()
  .then(res => {
    console.log(res === person) // true
  })

從結(jié)果上看,盡管三者在不指定回調(diào)函數(shù)的情形下,“似乎”是不影響結(jié)果的。但前面提到 p1p1.then()、p1.catch()、p1.finally() 都是兩個(gè)不同的 Promise 實(shí)例對(duì)象,盡管這些實(shí)例對(duì)象的值是相等的。

在實(shí)際應(yīng)用場(chǎng)景中,我們應(yīng)該避免寫出這些“無(wú)意義”的代碼。但是我們?cè)谌W(xué)習(xí)它們的時(shí)候,應(yīng)該要知道。就是“用不用”和“會(huì)不會(huì)”是兩回事。

下一篇接著介紹 Promise.all()Promise.race() 等,未完待續(xù)...

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

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

  • 1. promise要解決的問(wèn)題: 腦筋急轉(zhuǎn)彎:把牛關(guān)進(jìn)冰箱里,要分幾步? 很顯然,這三個(gè)操作不能顛倒順序,否則任...
    月上秦少閱讀 1,716評(píng)論 0 3
  • Promise的含義: ??Promise是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和...
    呼呼哥閱讀 2,270評(píng)論 0 16
  • Promise含義 Promise是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更強(qiáng)大。所謂Pr...
    oWSQo閱讀 1,133評(píng)論 0 4
  • Promiese 簡(jiǎn)單說(shuō)就是一個(gè)容器,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果,語(yǔ)法上說(shuō),Pr...
    雨飛飛雨閱讀 3,487評(píng)論 0 19
  • 1. Promise 的含義 所謂Promise,簡(jiǎn)單說(shuō)就是一個(gè)容器,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)...
    ROBIN2015閱讀 581評(píng)論 0 0

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