摘要:引擎線程也稱為內(nèi)核,負(fù)責(zé)處理腳本程序例如引擎引擎線程負(fù)責(zé)解析腳本,運(yùn)行代碼。對象代表一個未完成但預(yù)計(jì)將來會完成的操作。注意一旦新建就會立即執(zhí)行它屬于,無法取消。
寫在前面:
第一遍學(xué)Promise時, 只是大概過了一遍, 感覺學(xué)的不夠深入, 這一篇算是對之前的一個總結(jié)吧. Promise在ES6中也屬于一個較難理解的一部分; 所以在學(xué)習(xí)一個比較難理解的知識點(diǎn)時, 我們可以圍繞這個知識點(diǎn)進(jìn)行展開,逐個去理解.
理解一個知識點(diǎn), 不妨先列出下面幾個問題.
Promise是用來干什么的?
Promise是什么?
Promise如何去創(chuàng)建,使用?
Promise的常用形式?
Promise的使用有哪些注意點(diǎn)?
異步相關(guān)背景介紹 瀏覽器內(nèi)核首先聊一下瀏覽器, 一直對瀏覽器的結(jié)構(gòu)比較好奇,查了很多資料總結(jié)就有下面一點(diǎn)相關(guān)總結(jié); 其中也借鑒其他人的一些東西.
瀏覽器是多進(jìn)程的,有主進(jìn)程, GPU加速進(jìn)程,渲染進(jìn)程(內(nèi)核)等, 一般新開一個tab頁面就是新啟動一個進(jìn)程, CPU就會給他分配資源; 但其中有一個核心進(jìn)程==>渲染進(jìn)程(瀏覽器內(nèi)核), 是我們前端人員需要特別關(guān)注的,它包括了多個線程...
GUI渲染線程
負(fù)責(zé)渲染瀏覽器界面,解析HTML,CSS,構(gòu)建DOM樹和RenderObject樹,布局和繪制等。 當(dāng)界面需要重繪(Repaint)或由于某種操作引發(fā)回流(reflow)時,該線程就會執(zhí)行 注意,GUI渲染線程與JS引擎線程是互斥的,當(dāng)JS引擎執(zhí)行時GUI線程會被掛起(相當(dāng)于被凍結(jié)了), GUI更新會被保存在一個隊(duì)列中等到JS引擎空閑時立即被執(zhí)行。
JS引擎線程
也稱為JS內(nèi)核,負(fù)責(zé)處理Javascript腳本程序.(例如V8引擎)JS引擎線程負(fù)責(zé)解析Javascript腳本,運(yùn)行代碼。 JS引擎一直等待著任務(wù)隊(duì)列中任務(wù)的到來,然后加以處理,一個Tab頁(renderer進(jìn)程)中無論什么時候都只有一個JS線程在運(yùn)行JS程序 同樣注意,GUI渲染線程與JS引擎線程是互斥的,所以如果JS執(zhí)行的時間過長,這樣就會造成頁面的渲染不連貫,導(dǎo)致頁面渲染加載阻塞。 不過H5中新增了Web Worker, 實(shí)現(xiàn)了多線程: js會新開線程來處理一些其他任務(wù),但不會影響DOM結(jié)構(gòu)... 創(chuàng)建Worker時,JS引擎向?yàn)g覽器申請開一個子線程(子線程是瀏覽器開的,完全受主線程控制,而且不能操作DOM) JS引擎線程與worker線程間通過特定的方式通信 (postMessage API,需要通過序列化對象來與線程交互特定的數(shù)據(jù))
事件觸發(fā)線程
這個線程是歸屬于瀏覽器而不是JS引擎,用來控制事件循環(huán)(可以理解,JS引擎自己都忙不過來,需要瀏覽器另開線程協(xié)助) 當(dāng)JS引擎執(zhí)行代碼塊如setTimeOut時(也可來自瀏覽器內(nèi)核的其他線程,如鼠標(biāo)點(diǎn)擊、AJAX異步請求, 頁面滾動等),會將對應(yīng)任務(wù)添加到事件線程中 當(dāng)對應(yīng)的事件符合觸發(fā)條件被觸發(fā)時,該線程會把事件添加到待處理隊(duì)列的隊(duì)尾,等待JS引擎的處理 注意, 由于JS的單線程關(guān)系,所以這些待處理隊(duì)列中的事件都得排隊(duì)等待JS引擎處理(當(dāng)JS引擎空閑時才會去執(zhí)行)
定時觸發(fā)器線程
即setInterval與setTimeout所在線程 瀏覽器定時計(jì)數(shù)器并不是由JavaScript引擎計(jì)數(shù)的,(因?yàn)镴avaScript引擎是單線程的, 如果處于阻塞線程狀態(tài)就會影響記計(jì)時的準(zhǔn)確); 因此通過多帶帶線程來計(jì)時并觸發(fā)定時(計(jì)時完畢后,添加到事件隊(duì)列中,等待JS引擎空閑后執(zhí)行) 當(dāng)然setTimeout中的延時參數(shù)也不一定準(zhǔn)確
異步HTTP請求線程
在XMLHttpRequest在連接后是通過瀏覽器新開一個網(wǎng)絡(luò)線程去請求 將檢測到狀態(tài)變更時,如果設(shè)置有回調(diào)函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件, 將這個回調(diào)再放入事件隊(duì)列中。再由JavaScript引擎執(zhí)行。
那么關(guān)于瀏覽器方面的背景知識就介紹到這里啦, 想要深入去了解,可以去查相關(guān)資料...
事件隊(duì)列和循環(huán)大家都知道JavaScript引擎是單線程的工作模式, 即同一時間只能跑一段代碼,還要按順序自上而下執(zhí)行; 但是碰到I/O操作, 定時器, 事件監(jiān)聽函數(shù)等這些耗時操作; JS引擎不會等待它們有結(jié)果了才去之下它們后面的代碼, 而是會將它們?nèi)舆M(jìn)任務(wù)(事件)隊(duì)列中, 等待同步代碼執(zhí)行棧空了之后, 再去任務(wù)隊(duì)列將任務(wù)一個個取出來執(zhí)行任務(wù)所對應(yīng)的回調(diào)函數(shù), 執(zhí)行完畢后會一直等待新的任務(wù)到來; 如此循環(huán)...
幾個類型的回調(diào)同步回調(diào)函數(shù)
我們可以利用了函數(shù)的執(zhí)行棧順序,函數(shù)作為參數(shù)放到另一個函數(shù)中調(diào)用, 誰在后面調(diào)用誰就先被放在函數(shù)執(zhí)行棧棧頂
異步回調(diào)函數(shù)
事先在外面定義好一個callback; 將回調(diào)函數(shù)作為某個函數(shù)的參數(shù), 利用函數(shù)的作用域?qū)⒑瘮?shù)中異步任務(wù)得到的結(jié)果存在回調(diào)函數(shù)的形參中, 然后在函數(shù)體末尾調(diào)用...
定時器
setTimeout的作用是在間隔一定的時間后,將回調(diào)函數(shù)插入任務(wù)隊(duì)列中,等棧中的同步任務(wù)都執(zhí)行完畢后,再執(zhí)行, 當(dāng)然這個時間不一定準(zhǔn)確...
看阮老師的ES6出門上說Promise是JS異步編程的一種解決方案. 舉個例子, Ajax的回調(diào)問題, 如果下一個ajax請求要用到上一個Ajax請求中的結(jié)果, 那么往往就會導(dǎo)致多個回調(diào)嵌套的問題, 那么Promise就可以解決這種代碼上的嵌套問題, 是我們的代碼變得更優(yōu)美, 更利于維護(hù); 我暫時先對Promise的理解就是: 處理異步任務(wù), 保存異步結(jié)果狀態(tài), 異步代碼同步化...
Promise是什么?Promise 它就是一個對象,相當(dāng)于一個容器, 里面存的就是一個異步操作的結(jié)果; 我們可以是從中獲取異步操作結(jié)果的相關(guān)信息。
Promise對象代表一個未完成、但預(yù)計(jì)將來會完成的操作。
它有以下三種狀態(tài):
pending:初始值,不是fulfilled,也不是rejected
fulfilled:代表操作成功
rejected:代表操作失敗
Promise有兩種狀態(tài)改變的方式,既可以從pending轉(zhuǎn)變?yōu)閒ulfilled,也可以從pending轉(zhuǎn)變?yōu)閞ejected。一旦狀態(tài)改變,就「凝固」了,會一直保持這個狀態(tài),不會再發(fā)生變化。當(dāng)狀態(tài)發(fā)生變化,promise.then綁定的函數(shù)就會被調(diào)用。
注意:Promise一旦新建就會「立即執(zhí)行」(它屬于microtask),無法取消。這也是它的缺點(diǎn)之一。
1.創(chuàng)建promise對象
//1.使用new Promise(func)的形式 //2.快捷語法: Promise.resolve(func) || Promise.reject(func) // 參數(shù)1: 一般是一個處理異步任務(wù)的函數(shù) // 返回值: 一個promise實(shí)例對象 Promise.resolve("foo") // 等價于, 不過參數(shù)類型不一樣執(zhí)行的操作也會有所不同 new Promise(resolve => resolve("foo"))
2.在函數(shù)func中 放異步處理代碼
// 傳入兩個參數(shù): 回調(diào)函數(shù)resolve, reject分別去保存異步處理的結(jié)果 // 成功: 使用resolve(結(jié)果) // 失敗: 使用reject(原因)
3.調(diào)用實(shí)例的then(func1) 或者 catch(err)
首先then方法是異步執(zhí)行, 對上面的異步結(jié)果進(jìn)行處理的函數(shù) 參數(shù): 傳回調(diào)函數(shù), 一個兩個都行, 前者是成功狀態(tài)的回調(diào),后者是失敗的回調(diào)Promise常用的場景?
promise一般的使用套路就是:
1.先定義一個函數(shù), 函數(shù)內(nèi)部使用new Promise()的方式來返回一個promise對象, resolve用來保存 異步處理成功的結(jié)果 reject用來保存 異常處理的結(jié)果 2.然后函數(shù)調(diào)用,傳參 3.鏈?zhǔn)秸Z法點(diǎn)出then方法, then中的回調(diào)用來處理異步結(jié)果 4.有錯誤就點(diǎn)出catch方法, 也可以用then(null, function() {})代替catch 5.then的回調(diào)中也可return一個值, 會被包裝成一個新的promise, 因此可以繼續(xù)調(diào)用then方法
應(yīng)用場景: 在ajax中使用, 解決異步嵌套問題
function ajax(url) { return new Promise((resolve, reject) => { let xhr = new XMLHttpRequest(); // 請求類型, 地址, 異步 xhr.open("get", url, true); xhr.send(); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { try { // 處理響應(yīng)內(nèi)容, 將內(nèi)容丟到成功狀態(tài)的回調(diào) resolve(JSON.parse(xhr.responseText)) } catch (e) { // 捕獲錯誤, 丟到失敗狀態(tài)的回調(diào) reject(e) } } } }); } // 調(diào)用 封裝的ajax函數(shù) let url = "http://127.0.0.1:3000/xxoo"; // 自己本地開的一個服務(wù) ajax(url) .then(res => console.log(res)) // 輸出 {code: 0, msg: "hello cors"} .catch(err => console.log(err)) ```
其他場景
// 實(shí)現(xiàn)串行任務(wù)管道; 即當(dāng)前任務(wù)的輸出可以作為下一個任務(wù)的輸入,形成一條數(shù)據(jù)管道; // 比如: 比如從url1獲取參數(shù)userId,拿到后再從url2獲取第三方openId,最后再從url3貨取orderList, 然后把結(jié)果展示給用戶,類似的邏輯都是任務(wù)管道: new Promise(function(resolve, reject) { resolve(1); }) .then(function(res) { return new Promise(function(resolve, reject) { resolve(res + 1); }); }) .then(function(res) { return new Promise(function(resolve, reject) { resolve(res + 1); }); }) .then(function(res) { console.log(res); // 3 });promise的好處
在異步執(zhí)行的流程中,使用Promise可以把 執(zhí)行代碼 和 處理結(jié)果 的代碼清晰地分離
這樣我們便可以 把執(zhí)行代碼 和 結(jié)果處理 分成不同的模塊來寫,易于維護(hù)
減少異步回調(diào)的嵌套, 比如ajax回調(diào), 我們可以依次調(diào)用then方法即可, 還可以控制回調(diào)的順序
多個異步任務(wù)是為了容錯去訪問用同一資源時, 可以使用Promise.race([promise實(shí)例...])
多個異步任務(wù)并行執(zhí)行時,比如ajax訪問兩個接口, 可以用Promise.all([promise實(shí)例...])
Promise使用的注意事項(xiàng)Promise構(gòu)造函數(shù)內(nèi)的同步代碼立即執(zhí)行
回調(diào)函數(shù)參數(shù)resolve異步執(zhí)行, 將結(jié)果作為參數(shù)傳給then方法中的回調(diào)函數(shù)
resolve只有第一次執(zhí)行有效,狀態(tài)不能二次改變
then和catch如果有return, 返回的是一個全新的promise對象, 可以鏈?zhǔn)秸{(diào)用
Promise構(gòu)造函數(shù)只會執(zhí)行一次, promise實(shí)例會保存resolve的狀態(tài),
以后這個實(shí)例每次調(diào)用then都是返回一個這個狀態(tài), 若鏈?zhǔn)秸{(diào)用then,下一個則會打印undefined, res沒有值...
then中返回任意一個非 promise 的值都會被包裹成 promise 對象
.then 或 .catch 返回的值不能是 promise 本身,否則會造成死循環(huán)
.then 或者 .catch 的參數(shù)期望是函數(shù),傳入非函數(shù)則會發(fā)生值穿透。
.then 可以接收兩個參數(shù),第一個是處理成功的函數(shù),第二個是處理錯誤的函數(shù)。.catch 是 .then 第二個參數(shù)的簡便寫法,但是它們用法上有一點(diǎn)需要注意:.then 的第二個處理錯誤的函數(shù)捕獲不了第一個處理成功的函數(shù)拋出的錯誤,而后續(xù)的 .catch 可以捕獲之前的錯誤。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/102596.html
Promise/async、await幫我們解決了什么 它給我們提供了一種新的異步編程解決方案,同時避免了困擾已久的回調(diào)地獄 // 異步的處理可能會產(chǎn)生這樣的回調(diào)地獄(第二個異步操作和第一個異步的結(jié)果有關(guān)系) let Ajax = function(data, success, error){ $.ajax({ data: data, success: function...
Promise/async、await幫我們解決了什么 它給我們提供了一種新的異步編程解決方案,同時避免了困擾已久的回調(diào)地獄 // 異步的處理可能會產(chǎn)生這樣的回調(diào)地獄(第二個異步操作和第一個異步的結(jié)果有關(guān)系) let Ajax = function(data, success, error){ $.ajax({ data: data, success: function...
Promise/async、await幫我們解決了什么 它給我們提供了一種新的異步編程解決方案,同時避免了困擾已久的回調(diào)地獄 // 異步的處理可能會產(chǎn)生這樣的回調(diào)地獄(第二個異步操作和第一個異步的結(jié)果有關(guān)系) let Ajax = function(data, success, error){ $.ajax({ data: data, success: function...
摘要:的翻譯文檔由的維護(hù)很多人說,阮老師已經(jīng)有一本關(guān)于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發(fā)過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:學(xué)習(xí)地址詳見正文調(diào)用或并不會終結(jié)的參數(shù)函數(shù)的執(zhí)行調(diào)用以后,后面的還是會執(zhí)行,并且會首先打印出來。這是因?yàn)榱⒓吹氖窃诒据喪录h(huán)的末尾執(zhí)行,總是晚于本輪循環(huán)的同步任務(wù)。另外,方法指定的回調(diào)函數(shù),如果運(yùn)行中拋出錯誤,也會被方法捕獲。 學(xué)習(xí)地址詳見:http://es6.ruanyifeng.com/#do... 正文 1.調(diào)用resolve或reject并不會終結(jié) Promise 的參數(shù)函...
閱讀 4189·2021-09-22 15:34
閱讀 2802·2021-09-22 15:29
閱讀 521·2019-08-29 13:52
閱讀 3375·2019-08-29 11:30
閱讀 2301·2019-08-26 10:40
閱讀 869·2019-08-26 10:19
閱讀 2283·2019-08-23 18:16
閱讀 2352·2019-08-23 17:50