摘要:參數(shù)如前面所提到的,方法只是方法的一個(gè)語(yǔ)法糖,原因就在于方法的參數(shù)為實(shí)際上是兩個(gè)回調(diào)函數(shù),分別用于處理調(diào)用它的對(duì)象的和狀態(tài),而方法就等價(jià)于狀態(tài)處理函數(shù)。對(duì)象狀態(tài)傳遞和改變的方法利用回調(diào)的返回值,可以控制某個(gè)操作后方法返回的對(duì)象及其狀態(tài)。
一分鐘快速入門(mén)注意,本文主要針對(duì)ES6標(biāo)準(zhǔn)實(shí)現(xiàn)的Promise語(yǔ)法進(jìn)行闡述,實(shí)例代碼也都使用ES6語(yǔ)法,快速入門(mén)ES6請(qǐng)參見(jiàn)ECMAScript 6 掃盲。
被回調(diào)地獄整怕了?快試Promise吧!。Promise的核心思想其實(shí)很簡(jiǎn)單,就是將異步操作結(jié)果處理交給Promise對(duì)象的方法注冊(cè),然后等到異步操作完了再去取用這些處理操作。至于取用哪個(gè)處理操作,就得看Promise對(duì)象狀態(tài)了。Promise對(duì)象一共有三種狀態(tài):Pending(初始狀態(tài))、Fulfilled(異步操作成功)、Rejected(異步操作失?。?。而三者間的轉(zhuǎn)換只有兩種情況:Pending—>Fulfilled、Pending—>Rejected;詳見(jiàn)下圖:
了解了狀態(tài)及其轉(zhuǎn)換后,我們就可以來(lái)使用Promise對(duì)象了:
let promise = new Promise((resolve, reject)=> { // 異步操作 // 異步操作成功時(shí)調(diào)用 resolve(value) // 異步操作失敗時(shí)調(diào)用 reject(error) });
上述代碼中傳給Promise構(gòu)造函數(shù)的兩個(gè)函數(shù)resolve, reject,分別用于觸發(fā)Promise對(duì)象的Fullfilled和Rejected狀態(tài)。當(dāng)處于Fullfilled狀態(tài)時(shí)Promise會(huì)調(diào)用then方法,而處于Rejected狀態(tài)時(shí)則會(huì)調(diào)用catch方法,這兩個(gè)方法都會(huì)返回Promise對(duì)象,所以我們可以采用鏈?zhǔn)綄?xiě)法:
promise.then((value)=> {...}) .catch((error)=> {...});
上面的方法鏈中,then方法里注冊(cè)了Fullfilled狀態(tài)的處理函數(shù)、catch方法則注冊(cè)了Rejected狀態(tài)的處理函數(shù)。這種簡(jiǎn)單明了的寫(xiě)法把異步操作的結(jié)果處理函數(shù)分離了出來(lái),如果這些處理本身又是異步操作,那我們自然也就把層層異步回調(diào)也從回調(diào)地獄中剝離了,代碼瞬間清爽有木有!
深入Promise調(diào)用鏈前面我們只是將一層處理操作分離到then方法中(其中catch方法只是then方法的一個(gè)語(yǔ)法糖,后面會(huì)再作講解);但在實(shí)際應(yīng)用中多個(gè)異步操作往往會(huì)以串行或并行的方式連續(xù)出現(xiàn),比如下面這個(gè)預(yù)定房間的流程:
其中數(shù)據(jù)校驗(yàn)、向API發(fā)送請(qǐng)求、往數(shù)據(jù)庫(kù)插入數(shù)據(jù)都是異步操作,一種用回調(diào)的寫(xiě)法大概長(zhǎng)這樣:
validate(data, (err)=> { if (err) return errorHandler(err); request(apiUrl, (err, apiResponse)=> { if (err) return errorHandler(err); if (apiResponse.isSuccessful) insertToDB(data, (err)=> { if (err) return errorHandler(err); successHandler(); }); else errorHandler(new Error("API error")); }); });
根據(jù)前面我們了解的Promise用法,我們已經(jīng)能將validate這個(gè)異步操作寫(xiě)成Promise形式了:
let promiseValidate = new Promise((resolve, reject)=> { validate(data, (err)=> { if (err) return reject(err); resolve(); }); }); promiseValidate(data) .then(()=> { request(apiUrl, (err, apiResponse)=> { if (err) return errorHandler(err); if (apiResponse.isSuccessful) insertToDB(data, (err)=> { if (err) return errorHandler(err); successHandler(); }); else errorHandler(new Error("API error")); }); }) .catch((err)=> errorHandler(err));
但要改就改到底,上面這種Promise和回調(diào)寫(xiě)法混合得就不倫不類(lèi),除了仍存在回調(diào)嵌套的問(wèn)題,多次出現(xiàn)的錯(cuò)誤判斷和處理也有點(diǎn)違反DRY。所以接下來(lái)我們會(huì)深入研究下Promise調(diào)用鏈的行為,重點(diǎn)探討then方法里注冊(cè)的回調(diào)對(duì)調(diào)用鏈上數(shù)據(jù)傳遞和Promise對(duì)象狀態(tài)變化的影響,以及如何在調(diào)用鏈上對(duì)錯(cuò)誤進(jìn)行統(tǒng)一的處理。
Promise.resolve和Promise.reject我們先來(lái)看下一種“快速”生成Promise對(duì)象的方法:直接調(diào)用Promise.resolve(value)或Promise.reject(err)。這種方法和new一個(gè)Promise對(duì)象的區(qū)別在于,Promise對(duì)象在生成的時(shí)候狀態(tài)就已經(jīng)確定,要么是Fullfilled(使用Promise.resolve())、要么是Rejected(使用Promise.reject()),不會(huì)和new實(shí)例化一樣等要異步操作完了再發(fā)生變化。
此外,如果傳給Promise.resolve方法的是一個(gè)具有then方法的對(duì)象(即所謂的Thenable對(duì)象),比如jQuery的$.ajax(),那么返回的Promise對(duì)象,后續(xù)調(diào)用的then就是原對(duì)象then方法的同一形式(參見(jiàn)下面的代碼)。簡(jiǎn)單來(lái)講,就是Promise.resolve會(huì)將Thenable對(duì)象轉(zhuǎn)為ES6的Promise對(duì)象,這一特性常被用來(lái)將Promise的不同實(shí)現(xiàn)轉(zhuǎn)換為ES6實(shí)現(xiàn)。
$.ajax("https://httpbin.org/ip").then((value)=> { /* 輸出223.65.191.59 */ console.log(value.origin) }); Promise.resolve($.ajax("https://httpbin.org/ip")) .then((value)=> { /* 輸出223.65.191.59 */ console.log(value.origin) });詳解Promise.prototype.then
有了前面知識(shí)的鋪墊,我們終于可以來(lái)詳細(xì)講一下Promise對(duì)象的then方法了。
參數(shù)如前面所提到的,catch方法只是then方法的一個(gè)語(yǔ)法糖,
原因就在于then方法的參數(shù)為實(shí)際上是“兩個(gè)”回調(diào)函數(shù),分別用于處理調(diào)用它的Promise對(duì)象的Fullfilled和Rejected狀態(tài),而catch方法就等價(jià)于then(undefined, Rejected狀態(tài)處理函數(shù))。
關(guān)于這兩個(gè)回調(diào)函數(shù),首先要注意它們是異步調(diào)用的:
var v = 1; /* 輸出result: 2 */ Promise.resolve().then(()=> {console.log("result: " + v)}); /* 輸出result: 2 */ Promise.reject().then(undefined, ()=> {console.log("result: " + v)}); v++;
而兩個(gè)回調(diào)函數(shù)的參數(shù),則是通過(guò)調(diào)用then方法的Promise對(duì)象指定的:
new Promise()產(chǎn)生的Promise對(duì)象,會(huì)分別用內(nèi)部resolve()、reject()函數(shù)的參數(shù)
Promise.resolve()或Promise.reject()產(chǎn)生的Promise對(duì)象,則分別用Promise.resolve()、Promise.reject()的參數(shù)
而兩個(gè)回調(diào)函數(shù)的返回值,會(huì)用Promise.resolve(第一個(gè)回調(diào)返回值)或Promise.reject(第二個(gè)回調(diào)返回值)的形式作包裝,用來(lái)“替換”then方法返回的Promise對(duì)象。結(jié)合上面提到的then回調(diào)函數(shù)參數(shù)指定方式,回調(diào)返回值會(huì)這樣影響下一個(gè)then的回調(diào)函數(shù):
返回的是普通數(shù)據(jù),會(huì)傳給下一級(jí)調(diào)用的then方法作為回調(diào)函數(shù)的參數(shù)
返回的是Promise對(duì)象或Thenable對(duì)象,會(huì)被拿來(lái)“替換”then方法返回的Promise對(duì)象,具體then的回調(diào)函數(shù)怎么調(diào)用和傳參就得看其內(nèi)部實(shí)現(xiàn)了
返回值一個(gè)新的Promise對(duì)象,狀態(tài)看執(zhí)行哪個(gè)回調(diào)函數(shù)決定。注意這是一個(gè)新對(duì)象,不是簡(jiǎn)單把調(diào)用then的Promise對(duì)象拿來(lái)改裝后返回:
var aPromise = new Promise((resolve)=> resolve(100)); var thenPromise = aPromise.then((value)=> console.log(value)); var catchPromise = thenPromise.catch((error)=> console.error(error)); /* true */ console.log(aPromise !== thenPromise); /* true */ console.log(thenPromise !== catchPromise);鏈?zhǔn)秸{(diào)用
知道了then方法的具體細(xì)節(jié)后,我們就能明白Promise調(diào)用鏈上:
傳遞數(shù)據(jù)的方法:利用上面提到的then回調(diào)的參數(shù)傳遞形式——不論是在Promise對(duì)象產(chǎn)生過(guò)程中直接傳遞、還是在then回調(diào)返回值中間接傳遞——就能實(shí)現(xiàn)將每一級(jí)異步操作的結(jié)果傳遞給后續(xù)then中注冊(cè)的處理函數(shù)處理。
Promise對(duì)象狀態(tài)傳遞和改變的方法:利用then回調(diào)的返回值,可以控制某個(gè)操作后then方法返回的Promise對(duì)象及其狀態(tài)。
現(xiàn)在我們把所有異步操作改為Promise語(yǔ)法,再利用在Promise調(diào)用鏈傳遞數(shù)據(jù)和控制狀態(tài)的方法,就能把本節(jié)開(kāi)始提到的預(yù)定房間操作中的回調(diào)嵌套都展開(kāi)來(lái)了:
let promiseValidate = new Promise((resolve, reject)=> { validate(data, (err)=> { if (err) return reject(err); resolve(); }); }); let promiseRequest = new Promise((resolve, reject)=> { request(data, (err, apiResponse)=> { if (err) return reject(err); // 在Promise對(duì)象產(chǎn)生過(guò)程中直接傳遞異步操作的結(jié)果 resolve(apiResponse); }); } ); let promiseInsertToDB = new Promise((resolve, reject)=> { insertToDB(data, (err)=> { if (err) return reject(err); resolve(); }); } ); promiseValidate(data) .then(()=> promiseRequest(apiUrl)) .then((apiResponse)=> { // 控制then回調(diào)的返回值,來(lái)改變then方法返回的新Promise對(duì)象的狀態(tài) if (apiResponse.isSuccessful) return insertToDB(data); else errorHandler(new Error("API error")); }) .then(()=> successHandler()) .catch((err)=> return errorHandler(err));
上面的代碼不僅將嵌套的代碼展開(kāi),讓我們掙脫了“回調(diào)地獄”;而且可以對(duì)異步操作的錯(cuò)誤直接利用統(tǒng)一的Promise錯(cuò)誤處理方法,避免寫(xiě)一堆重復(fù)的代碼。如果要進(jìn)一步DRY,可以抽象出一個(gè)將典型的Node.js回調(diào)接口封裝為Promise接口的函數(shù):
/* 處理形如 receiver.fn(...args, (err, res)=> {}) 的接口 */ let promisify = (fn, receiver) => { return (...args) => { // 返回重新封裝的Promise接口 return new Promise((resolve, reject) => { fn.apply(receiver, [...args, (err, res) => { // 重新綁定this return err ? reject(err) : resolve(res); }]); }); }; }; /* 用例 */ let promiseValidate = promisify(validate, global); let promiseRequest = promisify(request, global); let promiseInsertToDB = promisify(insertToDB, global);
Promise調(diào)用鏈上的錯(cuò)誤處理注意,由于resolve和reject方法只能接收一個(gè)參數(shù),所上面這個(gè)函數(shù)處理的回調(diào)里只能有err和一個(gè)數(shù)據(jù)參數(shù)。
在Promise調(diào)用鏈上的處理錯(cuò)誤的思路,就是去觸發(fā)Promise對(duì)象的Rejected狀態(tài),利用狀態(tài)的傳遞特性實(shí)現(xiàn)對(duì)錯(cuò)誤的捕獲,再在catch或then回調(diào)里處理這些錯(cuò)誤。下面我們就來(lái)進(jìn)行相關(guān)的探討:
錯(cuò)誤的捕獲首先我們有必要詳細(xì)了解下Promise對(duì)象的Rejected狀態(tài)的產(chǎn)生和傳遞過(guò)程。
Rejected狀態(tài)的產(chǎn)生有兩種情況:
調(diào)用了reject函數(shù):Promise對(duì)象實(shí)例化的回調(diào)調(diào)用了reject(),或者直接調(diào)用了Promise.reject()
通過(guò)throw拋出錯(cuò)誤
而只要產(chǎn)生了Rejected狀態(tài),就會(huì)在調(diào)用鏈上持續(xù)傳遞,直到遇見(jiàn)Rejected狀態(tài)的處理回調(diào)(catch的回調(diào)或then的第二個(gè)回調(diào))。再結(jié)合之前提到的Promise調(diào)用鏈上的數(shù)據(jù)傳遞方法,錯(cuò)誤就能在調(diào)用鏈上作為參數(shù)被相應(yīng)的回調(diào)“捕獲”了。這個(gè)過(guò)程可以參見(jiàn)下圖:
這里要注意,通過(guò)throw拋出錯(cuò)時(shí),如果錯(cuò)誤是在setTimeout等的回調(diào)中拋出,是不會(huì)讓Promise對(duì)象產(chǎn)生Rejected狀態(tài)的,這也以為著Promise調(diào)用鏈上捕獲不了這個(gè)錯(cuò)誤。舉個(gè)例子,下面這段代碼就不會(huì)有任何輸出:
Promise.resolve() .then(()=> setTimeout(100, ()=> {throw new Error("hi")})) .catch((err)=> console.log(err));
究其原因,是因?yàn)?b>setTimeout的異步操作和Promise的異步操作不屬于同一種任務(wù)隊(duì)列,setTimeout回調(diào)里的錯(cuò)誤會(huì)直接拋到全局變成Uncaught Error,而不會(huì)作用到Promise對(duì)象及其調(diào)用鏈上。這就也意味著,想要保證在調(diào)用鏈上產(chǎn)生的錯(cuò)誤能被捕獲,就必須始終使用調(diào)用reject函數(shù)的方式來(lái)產(chǎn)生和傳遞錯(cuò)誤。
錯(cuò)誤處理錯(cuò)誤處理可以在catch的回調(diào)或then的第二個(gè)回調(diào)里進(jìn)行。雖然前面提到catch方法等價(jià)于then(undefined, Rejected狀態(tài)處理函數(shù)),但推薦始終使用catch來(lái)處理錯(cuò)誤,原因有兩個(gè):
代碼的可讀性
對(duì)于then(Fullfilled狀處理函數(shù), Rejected狀態(tài)的處理函數(shù))這種寫(xiě)法,如果Fullfilled狀態(tài)的處理函數(shù)里出錯(cuò)了,那錯(cuò)誤只會(huì)繼續(xù)向下傳遞,同級(jí)的Rejected狀態(tài)處理函數(shù)沒(méi)辦法捕獲該錯(cuò)誤
優(yōu)化房間預(yù)訂例子的錯(cuò)誤處理了解完了Promise調(diào)用鏈上的錯(cuò)誤處理,我們?cè)賮?lái)回顧一開(kāi)始提到的房間預(yù)訂例子。之前我們的代碼里只是對(duì)異步操作中的可能出現(xiàn)錯(cuò)誤進(jìn)行了統(tǒng)一的處理,但是其中的API error等別的執(zhí)行錯(cuò)誤并未使用在Promise調(diào)用鏈上捕獲和處理錯(cuò)誤的方式。為了進(jìn)一步DRY,我們可以通過(guò)調(diào)用Promise.reject,強(qiáng)制將返回的Promise對(duì)象變?yōu)镽ejected狀態(tài),共用統(tǒng)一的Promise錯(cuò)誤處理:
(apiResponse)=> { if (apiResponse.isSuccessful) return insertToDB(data); // 返回的Promise對(duì)象為Rejected狀態(tài),共用統(tǒng)一的Promise錯(cuò)誤處理 else return Promise.reject(new Error("API error")); }Promise.all和Promise.race
前面研究的多個(gè)異步操作間往往具有前后依賴(lài)關(guān)系,或者說(shuō)它們是“串行”進(jìn)行的,只有前一個(gè)完成了才能進(jìn)行后一個(gè)。但有時(shí)我們處理的異步操作間可能并不具有依賴(lài)關(guān)系,比如處理多張圖片,這時(shí)再使用上面的調(diào)用鏈寫(xiě)法,就只能等處理完一張圖片、對(duì)應(yīng)的Promise對(duì)象狀態(tài)變化了,才能再去處理下一張,就顯得很低效了。所以,我們需要一種能在調(diào)用鏈中同時(shí)處理多個(gè)Promise對(duì)象的方法,Promise.all和Promise.race就是這樣應(yīng)運(yùn)而生的。
這兩個(gè)方法的相同點(diǎn)是會(huì)接受一個(gè)Promise對(duì)象組成的數(shù)組作為參數(shù),包裝返回成一個(gè)新的Promise實(shí)例。而它們的區(qū)別就在于返回的這個(gè)Promise實(shí)例狀態(tài)如何變化:
Promise.all:
所有傳入的Promise對(duì)象狀態(tài)都變成Fullfilled,最終狀態(tài)才會(huì)變成Fullfilled;此時(shí)便會(huì)調(diào)用Promise.resolve(各Promise對(duì)象resolve參數(shù)組成的數(shù)組),生成新?tīng)顟B(tài)的Promise對(duì)象返回
各個(gè)Promise對(duì)象若有一個(gè)被reject,最終狀態(tài)就變成Rejected;此時(shí)便會(huì)調(diào)用Promise.reject(第一個(gè)被reject的實(shí)例的reject參數(shù)),生成新?tīng)顟B(tài)的Promise對(duì)象返回
Promise.race:只要傳入的各個(gè)Promise對(duì)象中有一個(gè)率先改變狀態(tài)(Fullfilled或Rejected),返回的Promise對(duì)象狀態(tài)就會(huì)改變?yōu)橄鄳?yīng)狀態(tài)
有了這兩個(gè)方法,我們就能在Promise調(diào)用鏈上“并行”等待某些異步操作了,還是用前面提到的客房例子來(lái)舉例,如果我們?cè)陬A(yù)定房間時(shí)需要請(qǐng)求的API不止一個(gè),調(diào)用鏈可以這么寫(xiě):
promiseValidate(data) /* 請(qǐng)求多個(gè)API */ .then(()=> Promise.all([promiseRequest(apiUrl1), promiseRequest(apiUrl2)])) .then((apiResponse)=> { /* 傳給下個(gè)then回調(diào)的是一個(gè)resolve參數(shù)組成的數(shù)組 */ if (apiResponse[0].isSuccessful && apiResponse[1].isSuccessful) return insertToDB(data); else return Promise.reject(new Error("API error")); }) .then(()=> successHandler()) .catch((err)=> return errorHandler(err));Promise的應(yīng)用
Promise是一種異步調(diào)用的寫(xiě)法,自然是用來(lái)寫(xiě)出清晰的異步代碼、讓我們擺脫回調(diào)寫(xiě)法帶來(lái)的種種弊端,本文一直使用的預(yù)定房間例子就是一個(gè)佐證。不過(guò)考慮實(shí)際的應(yīng)用場(chǎng)景,還是有一些需要注意的地方:
前端異步處理前端的瀏覽器兼容性是阻礙新技術(shù)運(yùn)用的一大難題,雖然使目前瀏覽器對(duì)于ES6的支持越來(lái)越完善了,但除非你不考慮IE(兼容性表),否則在前端代碼里直接使用的原生的Promise實(shí)現(xiàn)并不太現(xiàn)實(shí)。對(duì)于這種情況,我們可以用一些Polyfill或拓展類(lèi)庫(kù)來(lái)讓我們能寫(xiě)Promise代碼。
Node的異步處理:Node.js環(huán)境下對(duì)ES6的Promise支持,在零點(diǎn)幾版開(kāi)始就有了,所以我們?cè)诰帉?xiě)服務(wù)器代碼、或者寫(xiě)一些跑在Node上的模塊時(shí)可以直接上Promise語(yǔ)法。不過(guò)要注意的是,Node上的大部分模塊開(kāi)放的API,還是默認(rèn)使用回調(diào)風(fēng)格,這是為了方便用戶(hù)在不了解Promise語(yǔ)法時(shí)快速上手;所以一般自己寫(xiě)的模塊API也會(huì)遵循這個(gè)慣例,至于模塊內(nèi)部實(shí)現(xiàn)那就隨你的意愿使用了。
還有一個(gè)要值得注意的是,最近Node實(shí)現(xiàn)了更優(yōu)雅的異步寫(xiě)法--async函數(shù),不過(guò)新的寫(xiě)法是基于Promise實(shí)現(xiàn)的,所以雖然async函數(shù)的出現(xiàn)讓Promise有種高不成低不就的感覺(jué),但了解Promise的用法還是很有必要的,希望本文能幫你做到這點(diǎn):D。
參考JavaScript Promise迷你書(shū)
Promise 的鏈?zhǔn)秸{(diào)用與中止
如何把 Callback 接口包裝成 Promise 接口
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/82835.html
摘要:學(xué)習(xí)開(kāi)發(fā),無(wú)論是前端開(kāi)發(fā)還是都避免不了要接觸異步編程這個(gè)問(wèn)題就和其它大多數(shù)以多線(xiàn)程同步為主的編程語(yǔ)言不同的主要設(shè)計(jì)是單線(xiàn)程異步模型。由于異步編程可以實(shí)現(xiàn)非阻塞的調(diào)用效果,引入異步編程自然就是順理成章的事情了。 學(xué)習(xí)js開(kāi)發(fā),無(wú)論是前端開(kāi)發(fā)還是node.js,都避免不了要接觸異步編程這個(gè)問(wèn)題,就和其它大多數(shù)以多線(xiàn)程同步為主的編程語(yǔ)言不同,js的主要設(shè)計(jì)是單線(xiàn)程異步模型。正因?yàn)閖s天生的與...
摘要:即使耗時(shí)一秒的執(zhí)行完畢,再的,仍然先于執(zhí)行了,這很好地解釋了微任務(wù)優(yōu)先的原理。把整個(gè)代碼分割成了個(gè)宏觀任務(wù),這里不論是秒還是秒,都是一樣的。 js實(shí)現(xiàn)異步的幾種形式 回調(diào)函數(shù) 事件監(jiān)聽(tīng) - 事件驅(qū)動(dòng)模式 發(fā)布/訂閱 - 觀察者模式 Promises對(duì)象 js異步歷史 一個(gè) JavaScript 引擎會(huì)常駐于內(nèi)存中,它等待著我們把JavaScript 代碼或者函數(shù)傳遞給它執(zhí)行 在 ...
摘要:版本以及之前,本身還沒(méi)有異步執(zhí)行代碼的能力,宿主環(huán)境傳遞給引擎,然后按順序執(zhí)行,由宿主發(fā)起任務(wù)。采納引擎術(shù)語(yǔ),把宿主發(fā)起的任務(wù)稱(chēng)為宏觀任務(wù),把引擎發(fā)起的任務(wù)稱(chēng)為微觀任務(wù)?;居梅ㄊ纠幕卣{(diào)是一個(gè)異步的執(zhí)行過(guò)程。 筆記說(shuō)明 重學(xué)前端是程劭非(winter)【前手機(jī)淘寶前端負(fù)責(zé)人】在極客時(shí)間開(kāi)的一個(gè)專(zhuān)欄,每天10分鐘,重構(gòu)你的前端知識(shí)體系,筆者主要整理學(xué)習(xí)過(guò)程的一些要點(diǎn)筆記以及感悟,完整的...
摘要:版本以及之前,本身還沒(méi)有異步執(zhí)行代碼的能力,宿主環(huán)境傳遞給引擎,然后按順序執(zhí)行,由宿主發(fā)起任務(wù)。采納引擎術(shù)語(yǔ),把宿主發(fā)起的任務(wù)稱(chēng)為宏觀任務(wù),把引擎發(fā)起的任務(wù)稱(chēng)為微觀任務(wù)?;居梅ㄊ纠幕卣{(diào)是一個(gè)異步的執(zhí)行過(guò)程。 筆記說(shuō)明 重學(xué)前端是程劭非(winter)【前手機(jī)淘寶前端負(fù)責(zé)人】在極客時(shí)間開(kāi)的一個(gè)專(zhuān)欄,每天10分鐘,重構(gòu)你的前端知識(shí)體系,筆者主要整理學(xué)習(xí)過(guò)程的一些要點(diǎn)筆記以及感悟,完整的...
閱讀 3134·2021-09-22 15:59
閱讀 1378·2021-08-30 09:46
閱讀 2353·2019-08-30 15:54
閱讀 2074·2019-08-26 12:15
閱讀 2607·2019-08-26 12:09
閱讀 1406·2019-08-26 11:57
閱讀 3395·2019-08-23 17:11
閱讀 1944·2019-08-23 15:59