關於 ES6 中 Promise 的面試題
說明
最近在複習 Promise 的知識,所以就做了一些題,這裡挑出幾道題,大家一起看看吧。
題目一
const promise = new Promise((resolve, reject) => {
console.log(1);
resolve();
console.log(2);
})
promise.then(() => {
console.log(3);
})
console.log(4);
解析
首先 Promise 新建後立即執行,所以會先輸出 1,2,而 Promise.then()
內部的程式碼在 當次 事件迴圈的 結尾 立刻執行 ,所以會繼續輸出4,最後輸出3。
答案
1
2
4
3
題目二
const promise = new Promise((resolve, reject) => {
resolve('success1');
reject('error');
resolve('success2');
});
promise.then((res) => {
console.log('then:', res);
}).catch((err) => {
console.log('catch:', err);
})
解析
resolve 函式
將 Promise 物件的狀態從“未完成”變為“成功”
(即從 pending 變為 resolved
),在非同步操作成功時呼叫,並將非同步操作的結果,作為引數傳遞出去;
reject 函式
將 Promise 物件的狀態從“未完成”變為“失敗”
(即從 pending 變為 rejected
),在非同步操作失敗時呼叫,並將非同步操作報出的錯誤,作為引數傳遞出去。
而一旦狀態改變,就不會再變。
所以 程式碼中的reject('error');
不會有作用。
Promise 只能 resolve 一次,剩下的呼叫都會被忽略。
所以 第二次的 resolve('success2');
也不會有作用。
答案
then: success1
題目三
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
解析
Promise.resolve
方法的引數如果是一個原始值,或者是一個不具有 then
方法的物件,則 Promise.resolve
方法返回一個新的 Promise
物件,狀態為resolved
,Promise.resolve
方法的引數,會同時傳給回撥函式。
then
方法接受的引數是函式,而如果傳遞的並非是一個函式,它實際上會將其解釋為 then(null)
,這就會導致前一個 Promise
的結果會穿透下面。
答案
1
題目四
紅燈三秒亮一次,綠燈一秒亮一次,黃燈2秒亮一次;如何讓三個燈不斷交替重複亮燈?(用Promse實現)三個亮燈函式已經存在:
function red() {
console.log('red');
}
function green() {
console.log('green');
}
function yellow() {
console.log('yellow');
}
解析
紅燈三秒亮一次,綠燈一秒亮一次,黃燈2秒亮一次,意思就是3秒,執行一次 red 函式,2秒執行一次 green 函式,1秒執行一次 yellow 函式,不斷交替重複亮燈,意思就是按照這個順序一直執行這3個函式,這步可以就利用遞迴來實現。
答案
function red() {
console.log('red');
}
function green() {
console.log('green');
}
function yellow() {
console.log('yellow');
}
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();
題目五
實現 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]
解析
首先 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
控制非同步流程,我們要想辦法,讓這些函式,一個執行完之後,再執行下一個,看答案吧。
答案
// 儲存陣列中的函式執行後的結果
var data = [];
// Promise.resolve方法呼叫時不帶引數,直接返回一個resolved狀態的 Promise 物件。
var sequence = Promise.resolve();
ajaxArray.forEach(function (item) {
// 第一次的 then 方法用來執行陣列中的每個函式,
// 第二次的 then 方法接受陣列中的函式執行後返回的結果,
// 並把結果新增到 data 中,然後把 data 返回。
sequence = sequence.then(item).then(function (res) {
data.push(res);
return data;
});
})
// 遍歷結束後,返回一個 Promise,也就是 sequence, 他的 [[PromiseValue]] 值就是 data,
// 而 data(儲存陣列中的函式執行後的結果) 也會作為引數,傳入下次呼叫的 then 方法中。
return sequence;
題目六
以下程式碼最後輸出什麼?
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);
解析
這道題就其實和 Promise
的關係不太大,主要是需要理解 JS執行機制,才能很好的解決這道題,對於 JS 執行機制不瞭解的朋友推薦看看這篇文章
第一輪事件迴圈
先執行宏任務,主script ,new Promise立即執行,輸出【3】,
執行 p 這個new Promise 操作,輸出【7】,
發現 setTimeout,將回撥放入下一輪任務佇列(Event Queue),p 的 then,姑且叫做 then1,放入微任務佇列,發現 first 的 then,叫 then2,放入微任務佇列。執行console.log(4)
,輸出【4】,宏任務執行結束。
再執行微任務,執行 then1,輸出【1】,
執行 then2,輸出【2】。
到此為止,第一輪事件迴圈結束。開始執行第二輪。
第二輪事件迴圈
先執行宏任務裡面的,也就是 setTimeout 的回撥,輸出【5】。resolve(6)
不會生效,因為 p 這個 Promise 的狀態一旦改變就不會在改變了。
答案
3
7
4
1
2
5
題目七
有 8 個圖片資源的 url,已經儲存在陣列 urls
中(即urls = ['', ...., ''])
,而且已經有一個函式 function loadImg
,輸入一個 url 連結,返回一個 Promise,該 Promise 在圖片下載完成的時候 resolve,下載失敗則 reject。
但是我們要求,任意時刻,同時下載的連結數量不可以超過 3 個。
請寫一段程式碼實現這個需求,要求儘可能快速地將所有圖片下載完成。
var urls = ['https://www.kkkk1000.com/images/getImgData/getImgDatadata.jpg', 'https://www.kkkk1000.com/images/getImgData/gray.gif', 'https://www.kkkk1000.com/images/getImgData/Particle.gif', 'https://www.kkkk1000.com/images/getImgData/arithmetic.png', 'https://www.kkkk1000.com/images/getImgData/arithmetic2.gif', 'https://www.kkkk1000.com/images/getImgData/getImgDataError.jpg', 'https://www.kkkk1000.com/images/getImgData/arithmetic.gif', 'https://www.kkkk1000.com/images/wxQrCode2.png'];
function loadImg(url) {
return new Promise((resolve, reject) => {
const img = new Image()
img.on load = function () {
console.log('一張圖片載入完成');
resolve();
}
img.on error = reject
img.src = url
})
};
解析
題目的意思是需要我們這麼做,先併發請求 3 張圖片,當一張圖片載入完成後,又會繼續發起一張圖片的請求,讓併發數保持在 3 個,直到需要載入的圖片都全部發起請求。
用 Promise 來實現就是,先併發請求3個圖片資源,這樣可以得到 3 個 Promise,組成一個陣列,就叫promises
吧,然後不斷的呼叫 來返回最快改變狀態的 Promise,然後從陣列(promises
)中刪掉這個 Promise 物件,再加入一個新的 Promise,直到全部的 url 被取完,最後再使用 來處理一遍陣列(promises
)中沒有改變狀態的 Promise。
答案
var urls = ['https://www.kkkk1000.com/images/getImgData/getImgDatadata.jpg', 'https://www.kkkk1000.com/images/getImgData/gray.gif', 'https://www.kkkk1000.com/images/getImgData/Particle.gif', 'https://www.kkkk1000.com/images/getImgData/arithmetic.png', 'https://www.kkkk1000.com/images/getImgData/arithmetic2.gif', 'https://www.kkkk1000.com/images/getImgData/getImgDataError.jpg', 'https://www.kkkk1000.com/images/getImgData/arithmetic.gif', 'https://www.kkkk1000.com/images/wxQrCode2.png'];
// 如果你需要複製程式碼執行下,請把 下面程式碼 中 on load 和 on error 中間的空格刪掉
// 不要問我為什麼這樣做,我也很尷尬啊...
function loadImg(url) {
return new Promise((resolve, reject) => {
const img = new Image()
img.on load = function () {
console.log('一張圖片載入完成');
resolve();
}
img.on error = reject
img.src = url
})
};
function limitLoad(urls, handler, limit) {
// 對陣列做一個複製
const sequence = [].concat(urls)
let promises = [];
//併發請求到最大數
promises = sequence.splice(0, limit).map((url, index) => {
// 這裡返回的 index 是任務在 promises 的腳標,用於在 Promise.race 之後找到完成的任務腳標
return handler(url).then(() => {
return index
});
});
// 利用陣列的 reduce 方法來以佇列的形式執行
return sequence.reduce((last, url, currentIndex) => {
return last.then(() => {
// 返回最快改變狀態的 Promise
return Promise.race(promises)
}).catch(err => {
// 這裡的 catch 不僅用來捕獲 前面 then 方法丟擲的錯誤
// 更重要的是防止中斷整個鏈式呼叫
console.error(err)
}).then((res) => {
// 用新的 Promise 替換掉最快改變狀態的 Promise
promises[res] = handler(sequence[currentIndex]).then(() => { return res });
})
}, Promise.resolve()).then(() => {
return Promise.all(promises)
})
}
limitLoad(urls, loadImg, 3)
/*
因為 limitLoad 函式也返回一個 Promise,所以當 所有圖片載入完成後,可以繼續鏈式呼叫
limitLoad(urls, loadImg, 3).then(() => {
console.log('所有圖片載入完成');
}).catch(err => {
console.error(err);
})
*/
總結
這幾道題,有考查 Promise 基礎知識的,也有考對 Promise 靈活運用的,如果這些題你都做的很好的話,那你對 Promise 的理解應該是不錯的了。
最後,如果文中有不足或者錯誤的地方,還請小夥伴們指出,萬分感謝。
如果覺得文章說的內容不夠,最後有與題目相關的文章,可以看看。
參考
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/818/viewspace-2816125/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 關於 Promise 的 9 個面試題Promise面試題
- 關於ES6的PromisePromise
- ES6之Promise常見面試題Promise面試題
- Promise面試題Promise面試題
- 一個Promise面試題Promise面試題
- Promise 序列呼叫面試題Promise面試題
- 面試總結:Promise有關面試的知識點。面試Promise
- ES6中的PromisePromise
- 面試中關於nginx的問答面試Nginx
- 關於 flex 面試題總結Flex面試題
- 關於React面試題彙總React面試題
- 關於 0 == ‘aa’,返回 1 的面試題面試題
- Java 面試題關於方法的重寫Java面試題
- 關於Integer面試的一個問題面試
- 關於執行緒池的面試題執行緒面試題
- JS每日一題: 如何理解es6中的Promise?JS每日一題Promise
- ES6中的Promise物件Promise物件
- 面試中關於Redis的問題看這篇就夠了面試Redis
- 關於PHP字串的一道面試題PHP字串面試題
- 關於面試的思考面試
- es6中的promise解讀Promise
- 透過面試題來說說Promise面試題Promise
- 面試題:promise的鏈式怎麼實現的面試題Promise
- 關於Python爬蟲面試50道題Python爬蟲面試
- 面試官眼中的Promise面試Promise
- Java面試鍊金系列 (1) | 關於String類的常見面試題剖析Java面試題
- Java中JVM相關面試題-整理JavaJVM面試題
- 7個關於"this"面試題,你知道幾個?面試題
- 面試中關於多執行緒同步,你必須要思考的問題面試執行緒
- ES6常見面試題總結面試題
- ES6 Promise - 讓我們解開的面紗(遵循Promise/A+規範)Promise
- 面試關於 MySQL 的編寫面試MySql
- ES6中的Promise和Generator詳解Promise
- 技術乾貨:關於效能測試面試題及答案面試題
- ES6中Promise用法詳解Promise
- 28個關於PHP核心技術的面試題,助力跳槽!PHP面試題
- [面試專題]JS非同步之Promise,Generator,Async面試JS非同步Promise
- 面向面試題和實際應用談Promise面試題Promise