【前端】手寫代碼輸出題易錯點匯總

兩天更新完。

const promise = new Promise((resolve, reject) => {console.log(1);console.log(2);
});
promise.then(() => {console.log(3);
});
console.log(4);
//1
//2
//4

promise.then 是微任務,它會在所有的宏任務執行完之后才會執行,同時需要promise內部的狀態發生變化,因為這里內部沒有發生變化,一直處于pending狀態,所以不輸出3。

const promise1 = new Promise((resolve, reject) => {console.log('promise1')resolve('resolve1')
})
const promise2 = promise1.then(res => {console.log(res)
})
console.log('1', promise1);
console.log('2', promise2);
/*
promise1
1 Promise{<resolved>: resolve1}
2 Promise{<pending>}
resolve1
*/

直接打印Promise,會打印出它的狀態值和參數。

const promise = new Promise((resolve, reject) => {console.log(1);setTimeout(() => {console.log("timerStart");resolve("success");console.log("timerEnd");}, 0);console.log(2);
});
promise.then((res) => {console.log(res);
});
console.log(4);
/*
1
2
4
timerStart
timerEnd
success
*/Promise.resolve().then(() => {console.log('promise1');const timer2 = setTimeout(() => {console.log('timer2')}, 0)
});
const timer1 = setTimeout(() => {console.log('timer1')Promise.resolve().then(() => {console.log('promise2')})
}, 0)
console.log('start');
/*
start
promise1
timer1
promise2
timer2
*/

代碼執行過程如下:

  1. 首先,Promise.resolve().then是一個微任務,加入微任務隊列
  2. 執行timer1,它是一個宏任務,加入宏任務隊列
  3. 繼續執行下面的同步代碼,打印出start
  4. 這樣第一輪宏任務就執行完了,開始執行微任務Promise.resolve().then,打印出promise1
  5. 遇到timer2,它是一個宏任務,將其加入宏任務隊列,此時宏任務隊列有兩個任務,分別是timer1、timer2;
  6. 這樣第一輪微任務就執行完了,開始執行第二輪宏任務,首先執行定時器timer1,打印timer1;
  7. 遇到Promise.resolve().then,它是一個微任務,加入微任務隊列
  8. 開始執行微任務隊列中的任務,打印promise2;
  9. 最后執行宏任務timer2定時器,打印出timer2;
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);
})
/*
then:success1
考察的就是Promise的狀態在發生變化之后,就不會再發生變化
*/Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)
/*
1
*/

then方法接受的參數是函數,而如果傳遞的并非是一個函數,這就會導致前一個Promise的結果會傳遞下面。Promise.resolve(3) 是一個 Promise 對象,不是一個函數。所以這個參數也被忽略。

const promise1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('success')//狀態改變}, 1000)
})
const promise2 = promise1.then(() => {//注意這是promise2throw new Error('error!!!')
})
console.log('promise1', promise1)
console.log('promise2', promise2)
setTimeout(() => {console.log('promise1', promise1)console.log('promise2', promise2)
}, 2000)
/*
promise1 Promise {<pending>}
promise2 Promise {<pending>}
promise1 Promise {<fulfilled>: "success"}
promise2 Promise {<rejected>: Error: error!!}
*/Promise.resolve(1).then(res => {console.log(res);//輸出1return 2;//給到了最后的.then}).catch(err => {return 3;}).then(res => {console.log(res);//輸出2});
/*
1   
2
*/

Promise是可以鏈式調用的,由于每次調用 .then 或者 .catch 都會返回一個新的 promise,從而實現了鏈式調用, 它并不像一般任務的鏈式調用一樣return this。
上面的輸出結果之所以依次打印出1和2,是因為resolve(1)之后走的是第一個then方法,并沒有進catch里,所以第二個then中的res得到的實際上是第一個then的返回值。并且return 2會被包裝成resolve(2),被最后的then打印輸出2。

Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)//1

只需要記住一個原則:.then 或.catch 的參數期望是函數,傳入非函數則會發生值透傳。就是當它不存在。
第一個then和第二個then中傳入的都不是函數,一個是數字,一個是對象,因此發生了透傳,將resolve(1) 的值直接傳到最后一個then里,直接打印出1。

Promise.resolve().then(() => {return new Error('error!!!')
}).then(res => {console.log("then: ", res)
}).catch(err => {console.log("catch: ", err)
})
/*
"then: " "Error: error!!!"
*/

返回任意一個非 promise 的值都會被包裹成 promise 對象,因此這里的return new Error(‘error!!!’)也被包裹成了return Promise.resolve(new Error(‘error!!!’)),因此它會被then捕獲而不是catch。

const promise = Promise.resolve().then(() => {return promise;
})
promise.catch(console.err)
/*
Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
*/

這里其實是一個坑,.then 或 .catch 返回的值不能是 promise 本身,否則會造成死循環。

Promise.reject('err!!!').then((res) => {console.log('success', res)}, (err) => {console.log('error', err)}).catch(err => {console.log('catch', err)})//error err!!!

錯誤直接被then的第二個參數捕獲了,所以就不會被catch捕獲了

Promise.resolve('1').then(res => {console.log(res)}).finally(() => {console.log('finally')})
Promise.resolve('2').finally(() => {console.log('finally2')return '我是finally2返回的值'}).then(res => {console.log('finally2后面的then函數', res)})
/* 注意一下微任務隊列順序,Promise.resolve是同步代碼 因為創建了一個promise
1
finally2
finally
finally2后面的then函數 2
*/function runAsync (x) {const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))return p
}Promise.all([runAsync(1), runAsync(2), runAsync(3)]).then(res => console.log(res))
/*
1
2
3
[1, 2, 3]
*/function runAsync (x) {const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))return p
}
function runReject (x) {const p = new Promise((res, rej) => setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x))
/*
`Error: ${x}`并不會打印,作為rejected 的原因傳入
*/return p
}
Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)]).then(res => console.log(res)).catch(err => console.log(err))
/*
// 1s后輸出
1
3
// 2s后輸出
2
Error: 2 //進入catch
// 4s后輸出
4
*/function runAsync(x) {const p = new Promise(r =>setTimeout(() => r(x, console.log(x)), 1000));return p;
}
function runReject(x) {const p = new Promise((res, rej) =>setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x));return p;
}
Promise.race([runReject(0), runAsync(1), runAsync(2), runAsync(3)]).then(res => console.log("result: ", res)).catch(err => console.log(err));
/* 雖然race只捕獲一次,但settimeout回調函數輸出還是有的
0
Error: 0
1
2
3
*/async function async1() {console.log("async1 start");await async2();console.log("async1 end");
}
async function async2() {console.log("async2");
}
async1();
console.log('start')
/*
async1 start
async2
start
async1 end跳出async1函數后,執行同步代碼start;在一輪宏任務全部執行完之后,再來執行await后面的內容async1 end。
await后面的語句相當于放到了new Promise中,下一行及之后的語句相當于放在Promise.then中。
*/async function async1() {console.log("async1 start");await async2();console.log("async1 end");setTimeout(() => {console.log('timer1')}, 0)
}
async function async2() {setTimeout(() => {console.log('timer2')}, 0)console.log("async2");
}
async1();
setTimeout(() => {console.log('timer3')
}, 0)
console.log("start")
/*
async1 start
async2
start
async1 end
timer2
timer3
timer1
*/

代碼的執行過程如下:

  1. 首先進入async1,打印出async1 start;
  2. 之后遇到async2,進入async2,遇到定時器timer2,加入宏任務隊列,之后打印async2;
  3. 由于async2阻塞了后面代碼的執行,所以執行后面的定時器timer3,將其加入宏任務隊列,之后打印start;
  4. 然后執行async2后面的代碼,打印出async1 end,遇到定時器timer1,將其加入宏任務隊列;
  5. 最后,宏任務隊列有三個任務,先后順序為timer2,timer3,timer1,沒有微任務,所以直接所有的宏任務按照先進先出的原則執行。
async function async1 () {console.log('async1 start');await new Promise(resolve => {console.log('promise1')})console.log('async1 success');return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')
/*
script start
async1 start
promise1
script end
async1中await后面的Promise是沒有返回值的,也就是它的狀態始終是pending狀態,所以在await之后的內容是不會執行的,包括async1后面的 .then。
*/

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/902661.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/902661.shtml
英文地址,請注明出處:http://en.pswp.cn/news/902661.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

基于深度學習和單目測距的前車防撞及車道偏離預警系統

隨著人工智能與計算機視覺技術的飛速發展,高級駕駛輔助系統(ADAS)已成為現代汽車智能化的關鍵標志。它不僅能有效提升行車安全,還能為自動駕駛時代的全面到來奠定堅實基礎。本文深入剖析一套功能完備、基于深度學習模型的 ADAS 系統的架構與核心實現,帶您領略智能駕駛背后…

JWT(JSON Web Token)用戶認證

1、頒發token <!--JWT依賴--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency><dependency><groupId>javax.xml.bind</groupId>…

【質量管理】現代TRIZ(萃智)理論概述

一、什么是TRIZ理論 TRIZ理論,即發明問題解決理論(Teoriya Resheniya Izobreatatelskikh Zadatch),是由前蘇聯發明家根里奇阿奇舒勒(Genrich S. Altshuller)于1946年創立的。它是一門基于知識的、面向人的發明問題解決系統化方法學。TRIZ理論通過研究大量的專利,總結出技…

大模型學習筆記 day01 提示工程入門1.One-shot Few-shot提示學習法

如何應?和激發?語?模型的各??能? 提示?程 Prompt engineering 通過輸?更加合理的提示&#xff0c;引導模型進?更有效的結果輸出&#xff0c;本質上是?種引導和激發模型能?的?法更加輕量級的引導?法&#xff0c;嘗試和實施的?檻更低&#xff1b;問題是受限于模型…

FPGA初級項目10——基于SPI的DAC芯片進行數模轉換

FPGA初級項目10——基于SPI的DAC芯片進行數模轉換 DAC芯片介紹 DAC 芯片&#xff08;數字模擬轉換器&#xff09;是一種將數字信號轉換為連續模擬信號&#xff08;如電壓或電流&#xff09;的集成電路&#xff0c;廣泛應用于電子系統中&#xff0c;連接數字世界與模擬世界。 …

如何在 Windows上安裝 Python 3.6.5?

Windows 系統安裝步驟 下載安裝包 安裝包下載鏈接&#xff1a;https://pan.quark.cn/s/9294ca0fd46a 運行安裝程序 雙擊下載的 .exe 文件&#xff08;如 python-3.6.5.exe&#xff09;。 勾選 Add Python 3.6 to PATH&#xff08;重要&#xff01;這將自動配置環境變量&…

Cephalon端腦云:神經形態計算+邊緣AI·重定義云端算力

前引&#xff1a;當算力不再是“奢侈品” &#xff0c;在人工智能、3D渲染、科學計算等領域&#xff0c;算力一直是橫亙在個人與企業面前的“高墻”。高性能服務器價格動輒數十萬元&#xff0c;專業設備維護成本高&#xff0c;普通人大多是望而卻步。然而&#xff0c;Cephalon算…

【信息系統項目管理師】高分論文:論進度管理和成本管理(智慧城管平臺項目)

更多內容請見: 備考信息系統項目管理師-專欄介紹和目錄 文章目錄 論文1、規劃進度管理2、定義活動3、排列活動順序4、估算活動資源5、估算活動持續時間6、制定進度計劃7、控制進度論文 2018年8月,我作為項目經理參與了 XX市智慧城管平臺項目的建設,該項目投資500萬元人民幣…

WebAssembly:開啟高性能Web應用新時代

一、引言 隨著互聯網技術的飛速發展&#xff0c;Web應用的復雜度和性能要求越來越高。傳統的Web開發技術&#xff0c;如JavaScript&#xff0c;雖然功能強大&#xff0c;但在處理復雜計算和高性能需求時仍存在一些局限性。WebAssembly&#xff08;簡稱Wasm&#xff09;作為一種…

操作系統進程管理筆記

1. 進程的基本概念 1.1 進程的定義 進程就是運行中的程序。程序本身是沒有生命周期的&#xff0c;它只是存在磁盤上面的一些指令&#xff08;也可能是一些靜態數據&#xff09;。是操作系統讓這些字節運行起來&#xff0c;讓程序發揮作用。 1.2 CPU的時分共享 操作系統通過…

Python中random庫的應用

文章目錄 一、random 庫常用函數二、條件語句 隨機數示例1&#xff1a;隨機決定程序分支示例2&#xff1a;模擬概率事件 三、循環語句 隨機數示例1&#xff1a;循環直到滿足隨機條件示例2&#xff1a;隨機次數循環 四、隨機操作數據結構示例1&#xff1a;隨機打亂列表順序示例…

密碼學貨幣混幣器詳解及python實現

目錄 一、前言二、混幣器概述2.1 混幣器的工作原理2.2 關鍵特性三、數據生成與預處理四、系統架構與流程五、核心數學公式六、異步任務調度與 GPU 加速七、PyQt6 GUI 設計八、完整代碼實現九、自查測試與總結十、展望摘要 本博客聚焦 “密碼學貨幣混幣器實現”,以 Python + P…

各種各樣的bug合集

一、連不上數據庫db 1.可能是密碼一大包東西不對&#xff1b; 2.可能是里面某個port和數據庫不一樣&#xff08;針對于修改了數據庫但是連不上的情況&#xff09;&#xff1b; 3.可能是git代碼沒拉對&#xff0c;再拉一下代碼。? 二、沒有這個包 可能是可以#注釋掉。? …

面陣相機中M12鏡頭和遠心鏡頭的區別及性能優勢

以下是關于面陣相機中M12鏡頭和遠心鏡頭的區別及性能優勢的詳細分析&#xff0c;結合知識庫內容整理如下&#xff1a; 一、M12鏡頭與遠心鏡頭的核心區別 1. 設計原理與光學特性 特性M12鏡頭遠心鏡頭光學設計標準鏡頭設計&#xff0c;無特殊光學校正&#xff0c;依賴傳統光路。…

從內核到應用層:深度剖析信號捕捉技術棧(含sigaction系統調用/SIGCHLD回收/volatile內存屏障)

Linux系列 文章目錄 Linux系列前言一、進程對信號的捕捉1.1 內核對信號的捕捉1.2 sigaction()函數1.3 信號集的修改時機 二、可重入函數三、volatile關鍵字四、SIGCHLD信號 前言 Linux系統中&#xff0c;信號捕捉是指進程可以通過設置信號處理函數來響應特定信號。通過信號捕捉…

DDD領域驅動與傳統CRUD

DDD 是一套 應對復雜業務系統 的設計方法論&#xff0c;核心是 讓代碼直接映射業務邏輯&#xff0c;避免技術實現與業務需求脫節。 關鍵區別&#xff1a; 傳統開發&#xff1a;根據數據庫表寫 CRUD&#xff08;技術驅動&#xff09;。DDD&#xff1a;根據業務行為建模&#xf…

20. git diff

基本概述 git diff的作用是&#xff1a;比較代碼差異 基本用法 1.工作區 VS 暫存區 git diff [file]2.暫存區 VS 最新提交 git diff --staged [file] # 或 git diff --cached [file]3.工作區 VS 最新提交 git diff HEAD [file]高級用法 1.比較兩個提交間的差異 git dif…

大模型面經 | 春招、秋招算法面試常考八股文附答案(五)

大家好,我是皮先生!! 今天給大家分享一些關于大模型面試常見的面試題,希望對大家的面試有所幫助。 往期回顧: 大模型面經 | 春招、秋招算法面試常考八股文附答案(RAG專題一) 大模型面經 | 春招、秋招算法面試常考八股文附答案(RAG專題二) 大模型面經 | 春招、秋招算法…

Sql刷題日志(day5)

面試&#xff1a; 1、從數據分析角度&#xff0c;推薦模塊怎么用指標衡量&#xff1f; 推薦模塊主要目的是將用戶進行轉化&#xff0c;所以其主指標是推薦的轉化率推薦模塊的指標一般都通過埋點去收集用戶的行為并完成相應的計算而形成相應的指標數據&#xff0c;而這里的驅動…

封裝 element-ui 二次彈框

author 封裝 element-ui 彈框 param text 文本內容 &#xff08;不傳默認顯示 確定執行此操作嗎&#xff1f; &#xff09; param type 彈框類型&#xff08;不傳默認warning類型&#xff09; param title 彈框標題&#xff08;不傳默認顯示 提示 &#xff09; export fun…