摘要:執(zhí)行,輸出,宏任務(wù)執(zhí)行結(jié)束。到此為止,第一輪事件循環(huán)結(jié)束。參考入門阮一峰系列之我們來(lái)聊聊一道關(guān)于應(yīng)用的面試題阿里前端測(cè)試題關(guān)于中函數(shù)的理解與應(yīng)用這一次,徹底弄懂執(zhí)行機(jī)制一個(gè)面試題原生的所有方法介紹附一道應(yīng)用場(chǎng)景題目異步流程控制
說(shuō)明
最近在復(fù)習(xí) Promise 的知識(shí),所以就做了一些題,這里挑出幾道題,大家一起看看吧。
題目一const promise = new Promise((resolve, reject) => { console.log(1); resolve(); console.log(2); }) promise.then(() => { console.log(3); }) console.log(4);解析
首先 Promise 新建后立即執(zhí)行,所以會(huì)先輸出 1,2,而 Promise.then() 內(nèi)部的代碼在 當(dāng)次 事件循環(huán)的 結(jié)尾 立刻執(zhí)行 ,所以會(huì)繼續(xù)輸出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 函數(shù)將 Promise 對(duì)象的狀態(tài)從“未完成”變?yōu)椤俺晒Α?/b>(即從 pending 變?yōu)?resolved),在異步操作成功時(shí)調(diào)用,并將異步操作的結(jié)果,作為參數(shù)傳遞出去;
reject 函數(shù)將 Promise 對(duì)象的狀態(tài)從“未完成”變?yōu)椤笆 ?/b>(即從 pending 變?yōu)?rejected),在異步操作失敗時(shí)調(diào)用,并將異步操作報(bào)出的錯(cuò)誤,作為參數(shù)傳遞出去。
而一旦狀態(tài)改變,就不會(huì)再變。
所以 代碼中的reject("error"); 不會(huì)有作用。
Promise 只能 resolve 一次,剩下的調(diào)用都會(huì)被忽略。
所以 第二次的 resolve("success2"); 也不會(huì)有作用。
then: success1題目三
Promise.resolve(1) .then(2) .then(Promise.resolve(3)) .then(console.log)解析
Promise.resolve 方法的參數(shù)如果是一個(gè)原始值,或者是一個(gè)不具有 then 方法的對(duì)象,則 Promise.resolve 方法返回一個(gè)新的 Promise 對(duì)象,狀態(tài)為resolved,Promise.resolve 方法的參數(shù),會(huì)同時(shí)傳給回調(diào)函數(shù)。
then 方法接受的參數(shù)是函數(shù),而如果傳遞的并非是一個(gè)函數(shù),它實(shí)際上會(huì)將其解釋為 then(null),這就會(huì)導(dǎo)致前一個(gè) Promise 的結(jié)果會(huì)穿透下面。
答案1題目四
紅燈三秒亮一次,綠燈一秒亮一次,黃燈2秒亮一次;如何讓三個(gè)燈不斷交替重復(fù)亮燈?(用Promse實(shí)現(xiàn))三個(gè)亮燈函數(shù)已經(jīng)存在:
function red() { console.log("red"); } function green() { console.log("green"); } function yellow() { console.log("yellow"); }解析
紅燈三秒亮一次,綠燈一秒亮一次,黃燈2秒亮一次,意思就是3秒,執(zhí)行一次 red 函數(shù),2秒執(zhí)行一次 green 函數(shù),1秒執(zhí)行一次 yellow 函數(shù),不斷交替重復(fù)亮燈,意思就是按照這個(gè)順序一直執(zhí)行這3個(gè)函數(shù),這步可以就利用遞歸來(lái)實(shí)現(xiàn)。
答案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();題目五
實(shí)現(xiàn) mergePromise 函數(shù),把傳進(jìn)去的數(shù)組按順序先后執(zhí)行,并且把返回的數(shù)據(jù)先后放到數(shù)組 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 => { // 在這里實(shí)現(xiàn)你的代碼 }; 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 都是函數(shù),只是這些函數(shù)執(zhí)行后會(huì)返回一個(gè) Promise,按題目的要求我們只要順序執(zhí)行這三個(gè)函數(shù)就好了,然后把結(jié)果放到 data 中,但是這些函數(shù)里都是異步操作,想要按順序執(zhí)行,然后輸出 1,2,3并沒有那么簡(jiǎn)單,看個(gè)例子。
function A() { setTimeout(function () { console.log("a"); }, 3000); } function B() { setTimeout(function () { console.log("b"); }, 1000); } A(); B(); // b // a
例子中我們是按順序執(zhí)行的 A,B 但是輸出的結(jié)果卻是 b,a 對(duì)于這些異步函數(shù)來(lái)說(shuō),并不會(huì)按順序執(zhí)行完一個(gè),再執(zhí)行后一個(gè)。
這道題就是考用 Promise 控制異步流程,我們要想辦法,讓這些函數(shù),一個(gè)執(zhí)行完之后,再執(zhí)行下一個(gè),看答案吧。
// 保存數(shù)組中的函數(shù)執(zhí)行后的結(jié)果 var data = []; // Promise.resolve方法調(diào)用時(shí)不帶參數(shù),直接返回一個(gè)resolved狀態(tài)的 Promise 對(duì)象。 var sequence = Promise.resolve(); ajaxArray.forEach(function (item) { // 第一次的 then 方法用來(lái)執(zhí)行數(shù)組中的每個(gè)函數(shù), // 第二次的 then 方法接受數(shù)組中的函數(shù)執(zhí)行后返回的結(jié)果, // 并把結(jié)果添加到 data 中,然后把 data 返回。 // 這里對(duì) sequence 的重新賦值,其實(shí)是相當(dāng)于延長(zhǎng)了 Promise 鏈 sequence = sequence.then(item).then(function (res) { data.push(res); return data; }); }) // 遍歷結(jié)束后,返回一個(gè) Promise,也就是 sequence, 他的 [[PromiseValue]] 值就是 data, // 而 data(保存數(shù)組中的函數(shù)執(zhí)行后的結(jié)果) 也會(huì)作為參數(shù),傳入下次調(diào)用的 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);解析
這道題就其實(shí)和 Promise 的關(guān)系不太大,主要是需要理解 JS執(zhí)行機(jī)制,才能很好的解決這道題,對(duì)于 JS 執(zhí)行機(jī)制不了解的朋友推薦看看這篇文章
這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制
第一輪事件循環(huán)先執(zhí)行宏任務(wù),主script ,new Promise立即執(zhí)行,輸出【3】,
執(zhí)行 p 這個(gè)new Promise 操作,輸出【7】,
發(fā)現(xiàn) setTimeout,將回調(diào)放入下一輪任務(wù)隊(duì)列(Event Queue),p 的 then,姑且叫做 then1,放入微任務(wù)隊(duì)列,發(fā)現(xiàn) first 的 then,叫 then2,放入微任務(wù)隊(duì)列。執(zhí)行console.log(4),輸出【4】,宏任務(wù)執(zhí)行結(jié)束。
再執(zhí)行微任務(wù),執(zhí)行 then1,輸出【1】,
執(zhí)行 then2,輸出【2】。
到此為止,第一輪事件循環(huán)結(jié)束。開始執(zhí)行第二輪。
先執(zhí)行宏任務(wù)里面的,也就是 setTimeout 的回調(diào),輸出【5】。
resolve(6) 不會(huì)生效,因?yàn)?p 這個(gè) Promise 的狀態(tài)一旦改變就不會(huì)在改變了。
3 7 4 1 2 5題目七
有 8 個(gè)圖片資源的 url,已經(jīng)存儲(chǔ)在數(shù)組 urls 中(即urls = ["http://example.com/1.jpg", ...., "http://example.com/8.jpg"]),而且已經(jīng)有一個(gè)函數(shù) function loadImg,輸入一個(gè) url 鏈接,返回一個(gè) Promise,該 Promise 在圖片下載完成的時(shí)候 resolve,下載失敗則 reject。
但是我們要求,任意時(shí)刻,同時(shí)下載的鏈接數(shù)量不可以超過(guò) 3 個(gè)。
請(qǐng)寫一段代碼實(shí)現(xiàn)這個(gè)需求,要求盡可能快速地將所有圖片下載完成。
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.onload = function () { console.log("一張圖片加載完成"); resolve(); } img.onerror = reject img.src = url }) };解析
題目的意思是需要我們這么做,先并發(fā)請(qǐng)求 3 張圖片,當(dāng)一張圖片加載完成后,又會(huì)繼續(xù)發(fā)起一張圖片的請(qǐng)求,讓并發(fā)數(shù)保持在 3 個(gè),直到需要加載的圖片都全部發(fā)起請(qǐng)求。
用 Promise 來(lái)實(shí)現(xiàn)就是,先并發(fā)請(qǐng)求3個(gè)圖片資源,這樣可以得到 3 個(gè) Promise,組成一個(gè)數(shù)組,就叫promises 吧,然后不斷的調(diào)用 Promise.race 來(lái)返回最快改變狀態(tài)的 Promise,然后從數(shù)組(promises )中刪掉這個(gè) Promise 對(duì)象,再加入一個(gè)新的 Promise,直到全部的 url 被取完,最后再使用 Promise.all 來(lái)處理一遍數(shù)組(promises )中沒有改變狀態(tài)的 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"]; function loadImg(url) { return new Promise((resolve, reject) => { const img = new Image() img.onload = function () { console.log("一張圖片加載完成"); resolve(); } img.onerror = reject img.src = url }) }; function limitLoad(urls, handler, limit) { // 對(duì)數(shù)組做一個(gè)拷貝 const sequence = [].concat(urls) let promises = []; //并發(fā)請(qǐng)求到最大數(shù) promises = sequence.splice(0, limit).map((url, index) => { // 這里返回的 index 是任務(wù)在 promises 的腳標(biāo),用于在 Promise.race 之后找到完成的任務(wù)腳標(biāo) return handler(url).then(() => { return index }); }); // 利用數(shù)組的 reduce 方法來(lái)以隊(duì)列的形式執(zhí)行 return sequence.reduce((last, url, currentIndex) => { return last.then(() => { // 返回最快改變狀態(tài)的 Promise return Promise.race(promises) }).catch(err => { // 這里的 catch 不僅用來(lái)捕獲 前面 then 方法拋出的錯(cuò)誤 // 更重要的是防止中斷整個(gè)鏈?zhǔn)秸{(diào)用 console.error(err) }).then((res) => { // 用新的 Promise 替換掉最快改變狀態(tài)的 Promise promises[res] = handler(sequence[currentIndex]).then(() => { return res }); }) }, Promise.resolve()).then(() => { return Promise.all(promises) }) } limitLoad(urls, loadImg, 3) /* 因?yàn)?limitLoad 函數(shù)也返回一個(gè) Promise,所以當(dāng) 所有圖片加載完成后,可以繼續(xù)鏈?zhǔn)秸{(diào)用 limitLoad(urls, loadImg, 3).then(() => { console.log("所有圖片加載完成"); }).catch(err => { console.error(err); }) */總結(jié)
這幾道題,有考查 Promise 基礎(chǔ)知識(shí)的,也有考對(duì) Promise 靈活運(yùn)用的,如果這些題你都做的很好的話,那你對(duì) Promise 的理解應(yīng)該是不錯(cuò)的了。
最后,如果文中有不足或者錯(cuò)誤的地方,還請(qǐng)小伙伴們指出,萬(wàn)分感謝。
如果覺得文章說(shuō)的內(nèi)容不夠,最后有與題目相關(guān)的文章,可以看看。
ECMAScript 6 入門 —— 阮一峰
ES6 系列之我們來(lái)聊聊 Promise
一道關(guān)于Promise應(yīng)用的面試題
阿里前端測(cè)試題--關(guān)于ES6中Promise函數(shù)的理解與應(yīng)用
這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制
一個(gè)Promise面試題
ES6原生Promise的所有方法介紹(附一道應(yīng)用場(chǎng)景題目)
Promise 異步流程控制
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/98822.html
摘要:函數(shù)的關(guān)鍵字的作用是停止執(zhí)行退出函數(shù)暫停執(zhí)行,等待方法調(diào)用停止執(zhí)行,可自行恢復(fù)執(zhí)行答案解析函數(shù)可以有很多個(gè)。簡(jiǎn)答題說(shuō)出至少個(gè)的新特性,并簡(jiǎn)述它們的作用。簡(jiǎn)答題答關(guān)鍵字,用于聲明只在塊級(jí)作用域起作用的變量。對(duì)象,更合理規(guī)范地處理異步操作。 通過(guò)對(duì)ES6系列文章的學(xué)習(xí),相信大家對(duì)ES6已結(jié)有一定程度的了解。 所以本節(jié)的目的在于通過(guò)測(cè)試,便于讓大家了解在學(xué)習(xí)中的知識(shí)掌握情況,查缺補(bǔ)漏,一步一...
答案自己谷歌或百度找。 一、來(lái)源背景 面試題是來(lái)自微博@??途W(wǎng)發(fā)布的真實(shí)大廠前端面經(jīng)題目,我一直在收集題目長(zhǎng)期一個(gè)一個(gè)的記錄下來(lái)的,可能會(huì)有重復(fù),但基本前端的面試大綱和需要掌握的知識(shí)都在其中了,面試題僅做學(xué)習(xí)參考,學(xué)習(xí)者閱后也要用心鉆研其中的原理,重要知識(shí)需要系統(tǒng)學(xué)習(xí)、透徹學(xué)習(xí),形成自己的知識(shí)鏈。 二、532道前端真實(shí)大廠面試題 express和koa的對(duì)比,兩者中間件的原理,koa捕獲異常多種情...
答案自己谷歌或百度找。 一、來(lái)源背景 面試題是來(lái)自微博@??途W(wǎng)發(fā)布的真實(shí)大廠前端面經(jīng)題目,我一直在收集題目長(zhǎng)期一個(gè)一個(gè)的記錄下來(lái)的,可能會(huì)有重復(fù),但基本前端的面試大綱和需要掌握的知識(shí)都在其中了,面試題僅做學(xué)習(xí)參考,學(xué)習(xí)者閱后也要用心鉆研其中的原理,重要知識(shí)需要系統(tǒng)學(xué)習(xí)、透徹學(xué)習(xí),形成自己的知識(shí)鏈。 二、532道前端真實(shí)大廠面試題 express和koa的對(duì)比,兩者中間件的原理,koa捕獲異常多種情...
答案自己谷歌或百度找。 一、來(lái)源背景 面試題是來(lái)自微博@??途W(wǎng)發(fā)布的真實(shí)大廠前端面經(jīng)題目,我一直在收集題目長(zhǎng)期一個(gè)一個(gè)的記錄下來(lái)的,可能會(huì)有重復(fù),但基本前端的面試大綱和需要掌握的知識(shí)都在其中了,面試題僅做學(xué)習(xí)參考,學(xué)習(xí)者閱后也要用心鉆研其中的原理,重要知識(shí)需要系統(tǒng)學(xué)習(xí)、透徹學(xué)習(xí),形成自己的知識(shí)鏈。 二、532道前端真實(shí)大廠面試題 express和koa的對(duì)比,兩者中間件的原理,koa捕獲異常多種情...
摘要:并總結(jié)經(jīng)典面試題集各種算法和插件前端視頻源碼資源于一身的文檔,優(yōu)化項(xiàng)目,在瀏覽器端的層面上提升速度,幫助初中級(jí)前端工程師快速搭建項(xiàng)目。 本文是關(guān)注微信小程序的開發(fā)和面試問(wèn)題,由基礎(chǔ)到困難循序漸進(jìn),適合面試和開發(fā)小程序。并總結(jié)vue React html css js 經(jīng)典面試題 集各種算法和插件、前端視頻源碼資源于一身的文檔,優(yōu)化項(xiàng)目,在瀏覽器端的層面上提升速度,幫助初中級(jí)前端工程師快...
閱讀 1670·2021-11-23 10:07
閱讀 2667·2019-08-30 11:10
閱讀 2850·2019-08-29 17:08
閱讀 1792·2019-08-29 15:42
閱讀 3188·2019-08-29 12:57
閱讀 2406·2019-08-28 18:06
閱讀 3555·2019-08-27 10:56
閱讀 394·2019-08-26 11:33