前端面試被Promise虐到了?這篇文章總結Promise知識及問題

小編認識了一個去找實習的同學,聊了實習找得怎樣了,讓我印象最深刻的就是她講promise的面試題,她說一面結束後就知道涼涼了,並且要是有機會很想和麵試官說一句:面試官對不起!我終於會了Promise!至於為什麼會這麼說,大家看看面試題及同學的回答就知道這位同學有多難受了。

面試題

CSS 實現水平垂直居中

flex的屬性

CSS transition的實現效果和有哪些屬性

CSS 實現沿Y軸旋轉360度 (直接自爆了 CSS不行。。。。麻了)

好,那來點JS 基本資料型別有哪些 用什麼判斷

陣列怎麼判斷

引用型別和基本型別的區別

什麼是棧?什麼是堆?

手寫 翻轉字串

手寫 Sum(1,2,3)的累加(argument)(我以為是柯里化,面試官笑了一下,腦筋不要這麼死嘛)

箭頭函式和普通函式的區別(上題忘記了argument,面試官特意問這個問題提醒我,奈何基礎太差救不起來了。。。淚目)

陣列去重的方法

圖片懶載入

跨域產生的原因,同源策略是什麼

說說你瞭解的解決辦法(只說了JSONP和CORS)

Cookie、sessionStorage、localStorage的區別

get 和 post 的區別 (只說了傳參方式和功能不同,面試官問還有嗎 其他的不知道了。。。)

問了一下專案,react

對ES6的瞭解 (Promise果真逃不了。。。。)

let var const的區別

知道Promise嘛?聊聊對Promise的理解?(說了一下Promise物件代表一個非同步操作,有三種狀態,狀態轉變為單向。。。)

那它是為了解決什麼問題的?(emmm當非同步返回值又需要等待另一個非同步就會巢狀回撥,Promise可以解決這個回撥地獄問題)

那它是如何解決回撥地獄的?(Promise物件內部是同步的,內部得到內部值後進行呼叫。then的非同步操作,可以一直。then 。then 。。。)

好,你說可以一直。then 。then 。。。那它是如何實現一直。then 的?(emmm。。。 這個。then鏈式呼叫就是。。。額這個。。。)

Promise有哪些方法 all和race區別是什麼

具體說一下 。catch() 和 reject (。。。我人麻了。。。)

結束環節

問了面試官對CSS的理解(必須但非重要,前端的核心還是儘量一比一還原設計稿,只有寫好了頁面才能考慮互動)

如何學習(基礎是最重要的,CSS和JS要注重實踐,蓋房子最重要的還是地基,所有的框架原始碼,元件等都基於CSS和JS)

曾經是如何度過這個過程的(多做專案,在專案中學習理解每個細節,再次告誡我基礎的重要性)

Promise概述

Promise是ES6新增的引用型別,可以透過new來進行例項化物件。Promise內部包含著非同步的操作。

new Promise(fn)

Promise。resolve(fn)

這兩種方式都會返回一個 Promise 物件。

Promise 有三種狀態:

等待態(Pending)、執行態(Fulfilled)和拒絕態(Rejected)

,且Promise 必須為三種狀態之一隻有非同步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。

狀態只能由 Pending 變為 Fulfilled 或由 Pending 變為 Rejected

,且狀態改變之後不會再發生變化,會一直保持這個狀態。

Pending 變為 Fulfilled 會得到一個私有

value

,Pending 變為 Rejected會得到一個私有

reason

,當Promise達到了Fulfilled或Rejected時,執行的非同步程式碼會接收到這個value或reason。

知道了這些,我們可以得到下面的程式碼:

實現原理

class Promise { constructor() { this。state = ‘pending’ // 初始化 未完成狀態 // 成功的值 this。value = undefined; // 失敗的原因 this。reason = undefined; }}複製程式碼

基本用法

Promise狀態只能在內部進行操作,內部操作在Promise執行器函式執行。Promise必須接受一個函式作為引數,我們稱該函式為執行器函式,執行器函式又包含resolve和reject兩個引數,它們是兩個函式。

resolve : 將Promise物件的狀態從 Pending(進行中) 變為 Fulfilled(已成功)

reject : 將Promise物件的狀態從 Pending(進行中) 變為 Rejected(已失敗),並丟擲錯誤。

使用栗子

let p1 = new Promise((resolve,reject) => { resolve(value);})setTimeout(() => { console。log((p1)); // Promise {: undefined}},1) let p2 = new Promise((resolve,reject) => { reject(reason);})setTimeout(() => { console。log((p2)); // Promise {: undefined}},1) 複製程式碼

實現原理

p1 resolve為成功,接收引數value,狀態改變為fulfilled,不可再次改變。

p2 reject為失敗,接收引數reason,狀態改變為rejected,不可再次改變。

如果executor執行器函式執行報錯,直接執行reject。

所以得到如下程式碼:

class Promise{ constructor(executor){ // 初始化state為等待態 this。state = ‘pending’; // 成功的值 this。value = undefined; // 失敗的原因 this。reason = undefined; let resolve = value => { console。log(value); if (this。state === ‘pending’) { // resolve呼叫後,state轉化為成功態 console。log(‘fulfilled 狀態被執行’); this。state = ‘fulfilled’; // 儲存成功的值 this。value = value; } }; let reject = reason => { console。log(reason); if (this。state === ‘pending’) { // reject呼叫後,state轉化為失敗態 console。log(‘rejected 狀態被執行’); this。state = ‘rejected’; // 儲存失敗的原因 this。reason = reason; } }; // 如果 執行器函式 執行報錯,直接執行reject try{ executor(resolve, reject); } catch (err) { reject(err); } } }複製程式碼

檢驗一下上述程式碼咯:

class Promise{。。。} // 上述程式碼new Promise((resolve, reject) => { console。log(0); setTimeout(() => { resolve(10) // 1 // reject(‘JS我不愛你了’) // 2 // 可能有錯誤 // throw new Error(‘是你的錯’) // 3 }, 1000)})複製程式碼

當執行程式碼1時輸出為

0

後一秒輸出

10

fulfilled 狀態被執行

當執行程式碼2時輸出為

0

後一秒輸出

我不愛你了

rejected 狀態被執行

當執行程式碼3時 丟擲錯誤

是你的錯

。then方法

promise。then(onFulfilled, onRejected)

初始化Promise時,執行器函式已經改變了Promise的狀態。且執行器函式是同步執行的。非同步操作返回的資料(成功的值和失敗的原因)可以交給。then處理,為Promise例項提供處理程式。

Promise例項生成以後,可以用then方法分別指定

resolved狀態

rejected狀態

的回撥函式。這兩個函式

onFulfilled,onRejected

都是可選的,不一定要提供。如果提供,則會Promise分別進入

resolved狀態

rejected狀態

時執行。

而且任何傳給then方法的

非函式型別引數

都會被靜默忽略。

then 方法必須返回一個

新的 promise 物件

(實現鏈式呼叫的關鍵)

實現原理

Promise只能轉換最終狀態一次,所以

onFulfilled

onRejected

兩個引數的操作是

互斥

當狀態state為

fulfilled

,則執行

onFulfilled

,傳入

this.value

。當狀態state為

rejected

,則執行

onRejected

,傳入

this.reason

class Promise { constructor(executor) { this。state = ‘pending’ // 初始化 未完成狀態 // 成功的值 this。value = undefined; // 失敗的原因 this。reason = undefined; // 。then 立即執行後 state為pengding 把。then儲存起來 this。onResolvedCallbacks = []; this。onRejectedCallbacks = []; // 把非同步任務 把結果交給 resolve let resolve = (value) => { if (this。state === ‘pending’) { console。log(‘fulfilled 狀態被執行’); this。value = value this。state = ‘fulfilled’ // onFulfilled 要執行一次 this。onResolvedCallbacks。forEach(fn => fn()); } } let reject = (reason) => { if (this。state === ‘pending’) { console。log(‘rejected 狀態被執行’); this。reason = reason this。state = ‘rejected’ this。onRejectedCallbacks。forEach(fn => fn()); } } try { executor(resolve, reject) } catch (e) { reject(err) } } // 一個promise解決了後(完成狀態轉移,把控制權交出來) then(onFulfilled, onRejected) { if (this。state == ‘pending’) { this。onResolvedCallbacks。push(() => { onFulfilled(this。value) }) this。onRejectedCallbacks。push(() => { onRejected(this。reason) }) } console。log(‘then’); // 狀態為fulfilled 執行成功 傳入成功後的回撥 把執行權轉移 if (this。state == ‘fulfiiied’) { onFulfilled(this。value); } // 狀態為rejected 執行失敗 傳入失敗後的回撥 把執行權轉移 if (this。state == ‘rejected’) { onRejected(this。reason) } }}let p1 = new Promise((resolve, reject) => { console。log(0); setTimeout(() => { // resolve(10) reject(‘JS我不愛你了’) console。log(‘setTimeout’); }, 1000)})。then(null,(data) => { console。log(data, ‘++++++++++’);})複製程式碼

0thenrejected 狀態被執行JS我不愛你了 ++++++++++setTimeout複製程式碼

當resolve在setTomeout內執行,then時state還是pending等待狀態 我們就需要在then呼叫的時候,將成功和失敗存到各自的陣列,一旦reject或者resolve,就呼叫它們。

現可以非同步實現了,但是還是不能鏈式呼叫啊? 為保證 then 函式鏈式呼叫,

then 需要返回 promise 例項

,再把這個promise返回的值傳入下一個then中。

Promise的各種方法

Promise。prototype。catch()

catch 異常處理函式,處理前面回撥中可能丟擲的異常。只接收一個引數

onRejected

處理程式。它相當於呼叫Promise。prototype。then(null,onRejected),所以它

也會返回一個新的Promise

例如

let p = new Promise((resolve, reject) => { setTimeout(() => { resolve(10) }, 1000)})。then(() => { throw Error(“1123”)})。catch((err) => { console。log(err);})。then(() => { console。log(‘異常捕獲後可以繼續。then’);})複製程式碼

當第一個。then的異常被捕獲後可以繼續執行。

Promise。all()

Promise。all()建立的Promise會在這一組Promise全部解決後在解決。也就是說會等待所有的promise程式都返回結果之後執行後續的程式。返回一個新的Promise。

例如

let p1 = new Promise((resolve, reject) => { resolve(‘success1’)})let p2 = new Promise((resolve, reject) => { resolve(‘success1’)})// let p3 = Promise。reject(‘failed3’)Promise。all([p1, p2])。then((result) => { console。log(result) // [‘success1’, ‘success2’] })。catch((error) => { console。log(error)})// Promise。all([p1,p3,p2])。then((result) => { // console。log(result)// })。catch((error) => { // console。log(error) // ‘failed3’ // // })複製程式碼

有上述例子得到,all的性質:

如果所有都成功,則合成Promise的返回值就是所有子Promise的返回值陣列。

如果有一個失敗,那麼第一個失敗的會把自己的理由作為合成Promise的失敗理由。

Promise。race()

Promise。race()是一組集合中最先解決或最先拒絕的Promise,返回一個新的Promise。

例如

let p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve(‘success1’) },1000)})let p2 = new Promise((resolve, reject) => { setTimeout(() => { reject(‘failed2’) }, 1500)})Promise。race([p1, p2])。then((result) => { console。log(result)})。catch((error) => { console。log(error) // ‘success1’ })複製程式碼

有上述例子得到,race的性質:

無論如何,最先執行完成的,就執行相應後面的。then或者。catch。誰先以誰作為回撥

總結

上面的Promise就總結到這裡有什麼理解也可以在下方評論區一起交流學習。

面試可以讓自己發現更多的知識盲點,從而促進自己學習,大家一起加油衝呀!!

這篇文章小夥伴們也別忘了

點贊+評論

噢!!!