第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開發(fā)者教程

ES6-10 入門教程

ES6+ Promise 基礎(chǔ)

1. 前言

我們知道瀏覽器在渲染網(wǎng)頁時(shí),會(huì)創(chuàng)建一個(gè)渲染進(jìn)程進(jìn)行渲染頁面,在渲染進(jìn)程中其中有 GUI 渲染線程和 JS 引擎線程(如 V8 引擎)兩個(gè)線程是互斥的。也就是說在同一時(shí)間內(nèi)只能有一個(gè)線程執(zhí)行。如果 JavaScript 執(zhí)行一段耗時(shí)程序時(shí)會(huì)阻止頁面渲染。如果要頁面快速在用戶面前呈現(xiàn)就要做一些優(yōu)化處理。對于不能立馬得到結(jié)果的程序,不需要等待,可以放到事件隊(duì)列中,等到得到結(jié)果后再執(zhí)行。

對這種不等待方式,JavaScript 提供了異步的解決方案,在 JavaScript 中常見的異步解決方案是 Callback 方式,而像 setTimeout 這樣提供異步的 API,還可以使用發(fā)布訂閱的來實(shí)現(xiàn)異步。使用回調(diào)函數(shù)存在回調(diào)地獄的問題。為了解決回調(diào)地獄,最早社區(qū)提出了 Promise 概念。最后在 ES6 時(shí)正式作為官方的解決方案,說明 Promise 有它獨(dú)有的優(yōu)勢。本節(jié)我們將學(xué)習(xí) Promise 的基本用法。

2. 回調(diào)地獄

我們都知道 JavaScript 異步使用的是回調(diào)函數(shù),下面我們來看一個(gè) ajax 請求的實(shí)例,下面的 ajax 方法是一個(gè)偽代碼,可以看作是請求接口的方法,接口請求的庫可以參考 jQuery 的 $.ajax 和 axios。

// ajax請求的偽代碼
function ajax(url, sucessCallback, failCallback) {
  // url:請求的url
  // sucessCallback:成功的回調(diào)函數(shù)
  // failCallback:失敗的回調(diào)函數(shù)
}

ajax(url1, (res1) => {
  ajax(url2, (res2) => {
    ajax(url3, (res3) => {
		doSomething(res1, res2, res3)
    })
  })
})

上面的 ajax 請求我們可以理解為,在調(diào)用 doSomething 方法時(shí)需要前面三個(gè)請求的結(jié)果作為參數(shù),所以只有前一個(gè) ajax 請求得到結(jié)果后才能發(fā)起第二個(gè)請求。這樣前后有依賴的嵌套被稱為回調(diào)地獄。對于比較復(fù)雜邏輯的情況來說,回調(diào)地獄會(huì)使程序出問題的概率大大增加。

另外,這樣做有個(gè)很嚴(yán)重的問題,就是接口請求的時(shí)間是三個(gè)請求的和,不能進(jìn)行并發(fā)操作,當(dāng)然我們也可以做一些優(yōu)化操作,如下:

let out = after(3, function (data){
  doSomething(...data)
})

ajax(url1, (res1) => {
  out(res1)
})
ajax(url2, (res2) => {
  out(res2)
})
ajax(url3, (res3) => {
  out(res3)
})

function after(times, callback) {
  const arr = [];
  return function (value){
    arr.push(value);
    if (--times==0) {
      callback(arr);
    }
  }
}

上面的代碼很優(yōu)雅地解決了回調(diào)嵌套的問題,但同時(shí)我們需要手動(dòng)維護(hù)一個(gè)計(jì)數(shù)器來控制最后的回調(diào)。這無疑增加了程序的復(fù)雜度,我們更希望的是關(guān)注我的業(yè)務(wù),而不是寫更多的邏輯來優(yōu)化。

針對這種情況,社區(qū)提供了很多這類優(yōu)化的庫,而 Promise 則是其中最亮眼的。對上面的情況,Promise 怎么解決的呢?看如下的實(shí)現(xiàn)方式:

function request(url) {
  return new Promise((resolve, reject) => {
    ajax(url, (res) => {
      resolve(res)
    })
  })
}
Promise.all([request(url1), request(url1), request(url1)]).then((result) => {
  doSomething(...result)
}).catch((error) => {
  console.log(error)
})

上面的代碼中我們封裝了一個(gè) request 請求的方法,通過 Promise.all() 來并發(fā)請求這些接口,當(dāng)接口都正確返回才會(huì)執(zhí)行 then 方法中的回調(diào),有一個(gè)錯(cuò)誤都會(huì)拋出異常。這種方式比較好的是,我們對請求進(jìn)行了封裝,不要再關(guān)注每一步請求是否完成做對應(yīng)的邏輯處理,讓我們在開發(fā)過程中更加關(guān)注業(yè)務(wù)邏輯,使開發(fā)效率更快。

3. Promise 用法

前面我們通過一個(gè)回調(diào)地獄的案例,說明了 Promise 的優(yōu)點(diǎn),就是為了解決異步而產(chǎn)生的。并且可以處理并發(fā)請求,很好地優(yōu)化了程序資源。

3.1 實(shí)例化一個(gè) Promise

首先需要明確 Promise 是一個(gè)類,我們在 VSCode 中輸入 new Promise() 會(huì)給我們?nèi)缦碌奶崾荆?/p>

圖片描述

new Promise() 時(shí)需要默認(rèn)需要傳入一個(gè)回調(diào)函數(shù),這個(gè)回調(diào)函數(shù)是 executor(執(zhí)行器),默認(rèn)會(huì)立即執(zhí)行。執(zhí)行器會(huì)提供兩個(gè)方法(resolve 和 reject)用于改變 promise 的狀態(tài)。resolve 會(huì)觸發(fā)成功狀態(tài),reject 會(huì)觸發(fā)失敗狀態(tài),無論成功或失敗都會(huì)傳入一個(gè)返回值,這個(gè)返回值會(huì)在實(shí)例調(diào)用 then 方法后作為響應(yīng)值獲取。

var promise = new Promise((resolve, reject) => {
  ajax(url, (data) => {
    resolve(data)	// 成功
  }, (error) => {
    reject(error)	// 失敗
  })
})

上面的代碼中實(shí)例化一個(gè) ajax 請求的 Promise, 當(dāng)接口請求成功就會(huì)調(diào)用 resolve () 方法把請求的值傳入進(jìn)去,如果失敗了就調(diào)用 reject () 方法把錯(cuò)誤信息傳入進(jìn)去。在后續(xù)的鏈?zhǔn)秸{(diào)用中獲取相應(yīng)的結(jié)果。

我們需要知道的是,Promise 有三個(gè)狀態(tài):等待(pending)、成功(fulfilled),失敗(rejected)。在初始化時(shí),這個(gè)狀態(tài)是等待態(tài),在等待狀態(tài)時(shí)可以轉(zhuǎn)化為成功態(tài)或失敗態(tài)。當(dāng)狀態(tài)是成功態(tài)或是失敗態(tài)后不能再被改變了。

上面的代碼中可以改變 Promise 狀態(tài)的是執(zhí)行器提供的 resolve 和 reject,resolve 會(huì)將等待態(tài)變?yōu)槌晒B(tài),reject 則會(huì)將等待態(tài)變?yōu)槭B(tài),在狀態(tài)變?yōu)槌晒蚴〉臓顟B(tài)時(shí)就不能被更改了。

3.2 then

在實(shí)例化 Promise 類后,我們?nèi)绾卧L問成功和失敗的值呢?Promise 提供了鏈?zhǔn)秸{(diào)用的 then 方法用于訪問成功的值和失敗的值,then 提供了兩個(gè)回調(diào) onfulfilled(成功回調(diào))、onrejected(失敗回調(diào))。

var promise = new Promise((resolve, reject) => {
  resolve(123);
  // reject('error')
  // throw new Error('Error')
})

promise
	.then(
    (data) => {
      console.log(data)	// 123
      return '100'
    },
    (reason) => {
      console.log(reason)
    }
  )
  .then((data) => {
      console.log(data)	// 100
  }, null)

上面的代碼中給我了幾個(gè)測試用例,有興趣的小伙伴可以進(jìn)行測試。then 方法返回一個(gè)值而不是 Promise 實(shí)例,并且會(huì)把這個(gè)結(jié)果返回到下一個(gè) then 的成功回調(diào)中;

如果返回的是一個(gè) promise,下一個(gè) then 會(huì)采用這個(gè) promise 結(jié)果,如果返回的是失敗,會(huì)傳到下一個(gè) then 中失敗的回調(diào)函數(shù)中去:

var promise = new Promise((resolve, reject) => {
  resolve(123);
})

promise
	.then(
    (data) => {
      return new Promise((resolve, reject) => {
        reject('錯(cuò)誤內(nèi)容');
      })
    },
    null
  )
  .then(null, (err) => {
      console.log('error:', err)	// error: 錯(cuò)誤內(nèi)容
  })

如果在失敗的回調(diào)函數(shù)中返回一個(gè)普通值或成功的 promise 也會(huì)走到下一層 then 的成功回調(diào)中去。

promise.then(null, (err) => {
	return '100';
}).then((data) => {
  console.log('data:', data);	// data: 123
}, null)

通過上面的例子可以知道,當(dāng)前 then 中走成功與否,主要看上一層返回的結(jié)果。總結(jié)有兩點(diǎn)。

  • 當(dāng)上一層返回一個(gè)普通值,或是一個(gè)成功的 Promise,則會(huì)走到下一層成功的回調(diào)函數(shù)中去;
  • 如果上一層返回一個(gè)失敗的 Promise,或是拋出一個(gè)異常,則會(huì)走到下一層的失敗的回調(diào)函數(shù)中去。

4. 小結(jié)

本節(jié)主要通過 JavaScript 中回調(diào)地獄的一個(gè)案例來引出為什么使用 Promise,以及 Promise 所帶來的好處。然后學(xué)習(xí)了 Promise 的基本使用和鏈?zhǔn)秸{(diào)用 then 方法,需要注意的是,then 中執(zhí)行成功或是失敗是根據(jù)它上一層的返回值,如果返回的是一個(gè)普通值或成功的 Promise 則會(huì)走 then 的成功回調(diào);如果拋出異?;蚍祷厥〉?Promise 則走 then 的失敗回調(diào)。