"Code tailor",爲前端開發者提供技術相關資訊以及系列基礎文章,微信關注「小和山的菜鳥們」公衆號,及時獲取最新文章。
在開始學習以前,咱們想要告訴您的是,本文章是對阮一峯《ECMAScript6 入門》一書中 "Promise" 章節的總結,若是您已掌握下面知識事項,則可跳過此環節直接進入題目練習javascript
若是您對某些部分有些遺忘,👇🏻 已經爲您準備好了!前端
Promise 的學習java
一個Promise
對象表明一個在這個Promise
被建立出來時不必定已知的值。它讓您可以把異步操做最終的成功返回值或者失敗緣由和相應的處理程序關聯起來。 這樣使得異步方法能夠像同步方法那樣返回值:異步方法並不會當即返回最終的值,而是會返回一個Promise
,以便在將來某個時候把值交給使用者。
三種狀態:es6
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('foo') }, 300) }) promise1 .then((value) => { console.log(value) // expected output: "foo" }) .catch((error) => { //發生錯誤時調用 console.log(error) }) .finally(() => { //不管正確或錯誤,都會執行 console.log('執行完畢') }) console.log(promise1) // expected output: [object Promise]
建立一個新的Promise
對象。該構造函數主要用於包裝尚未添加 promise 支持的函數。參數(executor
)爲兩個:resolve
函數,運算成功完成時調用;reject
函數,出錯時調用
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('foo') }, 300) }) promise1.then((value) => { console.log(value) // expected output: "foo" }) console.log(promise1) // expected output: [object Promise]
Promise.all()
方法接收一個 Promise 的iterable
類型(注:Array
,Map
,Set
都屬於ES6
的iterable
類型)的輸入,而且只返回一個Promise
實例。resolve
回調執行是在全部輸入的Promise
的resolve
回調都結束,或者輸入的iterable
裏沒有Promise
了的時候。reject 回調執行是隻要任何一個輸入的Promise
的reject
回調執行或者輸入不合法的Promise
就會當即拋出錯誤,而且reject
的是第一個拋出的錯誤信息。
const promise1 = Promise.resolve(3) const promise2 = 42 const promise3 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 'foo') }) Promise.all([promise1, promise2, promise3]).then((values) => { console.log(values) }) // expected output: Array [3, 42, "foo"]
該Promise.allSettled()
方法返回一個在全部給定的Promise
都已經fulfilled
或rejected
後的Promise
,並帶有一個對象數組,每一個對象表示對應的Promise
結果。當您有多個彼此不依賴的異步任務成功完成時,或者您老是想知道每一個Promise
的結果時,一般使用它。
const promise1 = Promise.resolve(3) const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo')) const promises = [promise1, promise2] Promise.allSettled(promises).then((results) => results.forEach((result) => console.log(result.status)), ) // expected output: // "fulfilled" // "rejected"
Promise.race(iterable)
方法返回一個Promise
,一旦迭代器中的某個Promise
解決或拒絕,返回的Promise
就會解決或拒絕。
const promise1 = new Promise((resolve, reject) => { setTimeout(resolve, 500, 'one') }) const promise2 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 'two') }) Promise.race([promise1, promise2]).then((value) => { console.log(value) // Both resolve, but promise2 is faster }) // expected output: "two"
優勢:ajax
缺點:數組
異步 callback
帶來的」回調地獄「,邏輯混亂,耦合性高,可讀性差催生了 Promise
,更多知識請點擊這裏JavaScript 的異步發展史promise
一:如下代碼最後輸出什麼?微信
const first = () => new Promise((resolve, reject) => { console.log(3) let p = new Promise((resolve, reject) => { console.log(7) setTimeout(() => { console.log(5) resolve(6) }, 0) resolve(1) }) resolve(2) p.then((arg) => { console.log(arg) }) }) first().then((arg) => { console.log(arg) }) console.log(4)
二:紅燈三秒亮一次,綠燈一秒亮一次,黃燈 2 秒亮一次;如何讓三個燈不斷交替重複亮燈?(用 Promise 實現)三個亮燈函數已經存在:異步
function red() { console.log('red') } function green() { console.log('green') } function yellow() { console.log('yellow') }
三:實現 mergePromise 函數,把傳進去的數組按順序前後執行,而且把返回的數據前後放到數組 data 中。函數
const timeout = (ms) => new Promise((resolve, reject) => { setTimeout(() => { resolve() }, ms) }) const ajax1 = () => timeout(2000).then(() => { console.log('1') return 1 }) const ajax2 = () => timeout(1000).then(() => { console.log('2') return 2 }) const ajax3 = () => timeout(2000).then(() => { console.log('3') return 3 }) const mergePromise = (ajaxArray) => { // 在這裏實現你的代碼 } mergePromise([ajax1, ajax2, ajax3]).then((data) => { console.log('done') console.log(data) // data 爲 [1, 2, 3] }) // 要求分別輸出 // 1 // 2 // 3 // done // [1, 2, 3]
1、
Answer:
// 運行結果: // => 3 // => 7 // => 4 // => 1 // => 2 // => 5
這道題主要理解 js 執行機制。
第一輪事件循環,先執行宏任務,主 script,new Promise
當即執行,輸出 3,執行 p 這個 new Promise
操做,輸出 7,發現 setTimeout
,將回調函數放入下一輪任務隊列(Event Quene
),p 的 then
,暫且命名爲 then1
,放入微任務隊列,且 first
也有 then
,命名爲 then2
,放入微任務隊列。執行 console.log(4)
,輸出 4,宏任務執行結束。
再執行微任務,執行 then1
,輸出 1,執行 then2
,輸出 3.
第一輪事件循環結束,開始執行第二輪。第二輪事件循環先執行宏任務裏面的,也就是 setTimeout
的回調,輸出 5.resolve(6)
不會生效,由於 p 的 Promise
狀態一旦改變就不會再變化了。
2、
Answer:
var light = function (timmer, cb) { return new Promise(function (resolve, reject) { setTimeout(function () { cb() resolve() }, timmer) }) } var step = function () { Promise.resolve() .then(function () { return light(3000, red) }) .then(function () { return light(2000, green) }) .then(function () { return light(1000, yellow) }) .then(function () { step() }) } step()
紅燈三秒亮一次,綠燈一秒亮一次,黃燈 2 秒亮一次,意思就是 3 秒,執行一次 red
函數,2 秒執行一次 green
函數,1 秒執行一次 yellow
函數,不斷交替重複亮燈,意思就是按照這個順序一直執行這 3 個函數,這步能夠就利用遞歸來實現。
固然,採用其餘方法能完成所示效果,方法不少,這邊只提供一種方式。
3、
Answer:
// 保存數組中的函數執行後的結果 var data = [] // Promise.resolve方法調用時不帶參數,直接返回一個resolved狀態的 Promise 對象。 var sequence = Promise.resolve() ajaxArray.forEach(function (item) { // 第一次的 then 方法用來執行數組中的每一個函數, // 第二次的 then 方法接受數組中的函數執行後返回的結果, // 並把結果添加到 data 中,而後把 data 返回。 // 這裏對 sequence 的從新賦值,實際上是至關於延長了 Promise 鏈 sequence = sequence.then(item).then(function (res) { data.push(res) return data }) }) // 遍歷結束後,返回一個 Promise,也就是 sequence, 他的 [[PromiseValue]] 值就是 data, // 而 data(保存數組中的函數執行後的結果) 也會做爲參數,傳入下次調用的 then 方法中。 return sequence
首先 ajax1
、ajax2
、ajax3
都是函數,只是這些函數執行後會返回一個 Promise
,按題目的要求咱們只要順序執行這三個函數就行了,而後把結果放到 data
中,可是這些函數裏都是異步操做,想要按順序執行,而後輸出 1,2,3 並無那麼簡單,看個例子。
function A() { setTimeout(function () { console.log('a') }, 3000) } function B() { setTimeout(function () { console.log('b') }, 1000) } A() B() // b // a
例子中咱們是按順序執行的 A,B 可是輸出的結果倒是 b,a 對於這些異步函數來講,並不會按順序執行完一個,再執行後一個。這道題就是考用 Promise
控制異步流程,咱們要想辦法,讓這些函數,一個執行完以後,再執行下一個。