promise鏈式調(diào)用和promise內(nèi)嵌套promise的學(xué)習(xí)

參考鏈接:

Promise.then鏈式調(diào)用順序?(這一篇詳細講解then中嵌套promise和各種情況說明河绽,必看,研究)

《ES6標準入門》(阮一峰)--16.Promise 對象?(這一篇講解promise比較全序仙,有promise的各種方法講解)

Promise基本使用及方法介紹?(promise講解比較全谬返,輔助參考)

Promise中then的執(zhí)行順序詳解?(有簡化版then實現(xiàn),參考)

面試官:“你能手寫一個 Promise 嗎”?(手寫then光涂,研究庞萍,未看)

題目七:并發(fā)加載三個圖片?

Promise的含義:

Promise 是一個對象,從它可以獲取異步操作的消息忘闻。Promise 是目前前端解決異步問題的統(tǒng)一方案

Promise對象有以下兩個特點:

(1)對象的狀態(tài)不受外界影響钝计。Promise對象代表一個異步操作,有三種狀態(tài):pending(進行中)齐佳、fulfilled(已成功)和rejected(已失斔教瘛)。

只有異步操作的結(jié)果炼吴,可以決定當(dāng)前是哪一種狀態(tài)本鸣,任何其他操作都無法改變這個狀態(tài)。

(2)一旦狀態(tài)改變硅蹦,就不會再變荣德,任何時候都可以得到這個結(jié)果闷煤。Promise 對象的狀態(tài)改變,只有兩種可能:從進行中變?yōu)橐殉晒蛷倪M行中變?yōu)橐咽 ?/p>

只要這兩種情況發(fā)生涮瞻,狀態(tài)就不會再變了鲤拿,會一直保持這個結(jié)果,這時就稱為 resolved(已定型)署咽。如果改變已經(jīng)發(fā)生了近顷,你再對 Promise 對象添加回調(diào)函數(shù),也會立即得到這個結(jié)果艇抠。

promise優(yōu)點:

promise對象幕庐,可以將 異步操作 以 同步操作的流程 表達出來,避免層層嵌套

Promise缺點:

首先家淤,無法取消Promise异剥,一旦新建它就會立即執(zhí)行,無法中途取消絮重。

其次冤寿,如果不設(shè)置回調(diào)函數(shù),Promise內(nèi)部拋出的錯誤青伤,不會反應(yīng)到外部督怜。

第三,當(dāng)處于進行中狀態(tài)時狠角,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)号杠。

promise的基本用法:

promise內(nèi)部是同步的,但是then方法是異步的

Promise構(gòu)造函數(shù)接受一個函數(shù)作為參數(shù)丰歌,該函數(shù)的兩個參數(shù)分別是resolve和reject姨蟋。它們是兩個函數(shù),由 JavaScript 引擎提供立帖,不用自己部署眼溶。

resolve 函數(shù)的作用是,將Promise 對象的狀態(tài)從“未完成”變?yōu)椤俺晒Α保磸?pending 變?yōu)?fulfilled)晓勇,在異步操作成功時調(diào)用堂飞,并將異步操作的結(jié)果,作為參數(shù)傳遞出去绑咱;

reject 函數(shù)的作用是绰筛,將Promise 對象的狀態(tài)從“未完成”變?yōu)椤笆 保磸?pending 變?yōu)?rejected),在異步操作失敗時調(diào)用描融,并將異步操作報出的錯誤别智,作為參數(shù)傳遞出去。

Promise實例生成以后稼稿,可以用then方法分別指定fulfilled狀態(tài)和rejected狀態(tài)的回調(diào)函數(shù)薄榛。

Promise.then(function(value) {

? ? // success

}, function(error) {

? ? // failure

})

then方法可以接受兩個回調(diào)函數(shù)作為參數(shù)。第一個回調(diào)函數(shù)是Promise 對象的狀態(tài)變?yōu)閞esolved時調(diào)用让歼,第二個回調(diào)函數(shù)是Promise 對象的狀態(tài)變?yōu)閞ejected時調(diào)用敞恋。

其中,第二個函數(shù)是可選的谋右,不一定要提供硬猫。這兩個函數(shù)都接受Promise 對象傳出的值作為參數(shù)。

下面是一個用Promise對象實現(xiàn)的 Ajax 操作的例子改执。

const getJSON = function(url) {

? const promise = new Promise(function(resolve, reject){

? ? const handler = function() {

? ? ? if (this.readyState !== 4) {

? ? ? ? return;

? ? ? }

? ? ? if (this.status === 200) {

? ? ? ? resolve(this.response);

? ? ? } else {

? ? ? ? reject(new Error(this.statusText));

? ? ? }

? ? };

? ? const client = new XMLHttpRequest();

? ? client.open("GET", url);

? ? client.onreadystatechange = handler;

? ? client.responseType = "json";

? ? client.setRequestHeader("Accept", "application/json");

? ? client.send();

? });

? return promise;

};

getJSON("/posts.json").then(function(json) {

? console.log('Contents: ' + json);

}, function(error) {

? console.error('出錯了', error);

});

resolve函數(shù)的參數(shù)除了正常的值以外啸蜜,還可能是另一個 Promise 實例

const p1 = new Promise(function (resolve, reject) {

? // ...

});

const p2 = new Promise(function (resolve, reject) {

? // ...

? resolve(p1);

})

上面代碼中,p1和p2都是 Promise 的實例辈挂,但是p2的resolve方法將p1作為參數(shù)衬横,即一個異步操作的結(jié)果是返回另一個異步操作。

注意终蒂,這時p1的狀態(tài)就會傳遞給p2蜂林,也就是說,p1的狀態(tài)決定了p2的狀態(tài)拇泣。如果p1的狀態(tài)是pending噪叙,那么p2的回調(diào)函數(shù)就會等待p1的狀態(tài)改變;

如果p1的狀態(tài)已經(jīng)是resolved或者rejected霉翔,那么p2的回調(diào)函數(shù)將會立刻執(zhí)行睁蕾。

Promise.prototype.then():

總結(jié)三點:

(1) 當(dāng)前一個then中的代碼都是同步執(zhí)行的,執(zhí)行結(jié)束后第二個then即可注冊進入微任務(wù)隊列债朵。

(2) 當(dāng)前一個then中有return 關(guān)鍵字子眶,需要return的內(nèi)容完全執(zhí)行結(jié)束,第二個then才會注冊進入微任務(wù)隊列。

(3)then 方法接受的參數(shù)是函數(shù)葱弟,而如果傳遞的并非是一個函數(shù)壹店,它實際上會將其解釋為 then(null),這就會導(dǎo)致前一個 Promise 的結(jié)果會穿透下面芝加。

Promise.resolve(1)

? .then(2)

? .then(Promise.resolve(3))

? .then(console.log)

// 1

Promise 實例具有then方法硅卢,也就是說,then方法是定義在原型對象Promise.prototype上的藏杖。它的作用是為 Promise 實例添加狀態(tài)改變時的回調(diào)函數(shù)将塑。

前面說過,then方法的第一個參數(shù)是resolved狀態(tài)的回調(diào)函數(shù)蝌麸,第二個參數(shù)(可選)是rejected狀態(tài)的回調(diào)函數(shù)点寥。

then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)来吩。因此可以采用鏈式寫法敢辩,即then方法后面再調(diào)用另一個then方法蔽莱。

const getJSON = ()=>(new Promise((resolve,reject)=>resolve(1)))

getJSON().then(function(json) {

console.log(json)

return json;

}).then(function(post) {

console.log(post)

});

上面的代碼使用then方法,依次指定了兩個回調(diào)函數(shù)戚长。第一個回調(diào)函數(shù)完成以后盗冷,會將返回結(jié)果作為參數(shù),傳入第二個回調(diào)函數(shù)同廉。

采用鏈式的then仪糖,可以指定一組按照次序調(diào)用的回調(diào)函數(shù)。這時迫肖,前一個回調(diào)函數(shù)锅劝,有可能返回的還是一個Promise對象(即有異步操作),

這時后一個回調(diào)函數(shù)蟆湖,就會等待該Promise對象的狀態(tài)發(fā)生變化故爵,才會被調(diào)用。

const getJSON = (num)=>(new Promise((resolve,reject)=>resolve(num)))

getJSON(1).then(function(post) {

return getJSON(2);

}).then(function (comments) {

console.log("resolved: ", comments);

}, function (err){

console.log("rejected: ", err);

});

// 打诱室觥:resolved:? 2

上面代碼中稠集,第一個then方法指定的回調(diào)函數(shù),返回的是另一個Promise對象饥瓷。這時剥纷,第二個then方法指定的回調(diào)函數(shù),就會等待這個新的Promise對象狀態(tài)發(fā)生變化呢铆。

如果變?yōu)閞esolved晦鞋,就調(diào)用第一個回調(diào)函數(shù),如果狀態(tài)變?yōu)閞ejected棺克,就調(diào)用第二個回調(diào)函數(shù)悠垛。

Promise.resolve():

promise.resolve()可以將對象轉(zhuǎn)換為promise對象

Promise.resolve('foo')

// 等價于

new Promise(resolve => resolve('foo'))

Promise.resolve方法的參數(shù)分成四種情況。

(1)參數(shù)是一個 Promise 實例

如果參數(shù)是 Promise 實例娜谊,那么Promise.resolve將不做任何修改确买、原封不動地返回這個實例。

(2)參數(shù)是一個thenable對象

thenable對象指的是具有then方法的對象纱皆,比如下面這個對象湾趾。

let thenable = {

? then: function(resolve, reject) {

? ? resolve(42);

? }

};

Promise.resolve方法會將這個對象轉(zhuǎn)為 Promise 對象,然后就立即執(zhí)行thenable對象的then方法派草。

let thenable = {

? then: function(resolve, reject) {

? ? resolve(42);

? }

};

let p1 = Promise.resolve(thenable);

p1.then(function(value) {

? console.log(value);? // 42

});

上面代碼中搀缠,thenable對象的then方法執(zhí)行后,對象p1的狀態(tài)就變?yōu)閞esolved近迁,從而立即執(zhí)行最后那個then方法指定的回調(diào)函數(shù)艺普,輸出 42。

(3)參數(shù)不是具有then方法的對象,或根本就不是對象

如果參數(shù)是一個原始值歧譬,或者是一個不具有then方法的對象岸浑,則Promise.resolve方法返回一個新的 Promise 對象,狀態(tài)為resolved瑰步。

const p = Promise.resolve('Hello');

p.then(function (s){

? console.log(s)

});

// Hello

上面代碼生成一個新的 Promise 對象的實例p助琐。由于字符串Hello不屬于異步操作(判斷方法是字符串對象不具有 then 方法),返回 Promise 實例的狀態(tài)從一生成就是resolved面氓,所以回調(diào)函數(shù)會立即執(zhí)行。Promise.resolve方法的參數(shù)蛆橡,會同時傳給回調(diào)函數(shù)舌界。

Promise.prototype.catch():

Promise.prototype.catch() 是 .then(null, rejection) 的別名,用于指定發(fā)生錯誤時的回調(diào)函數(shù)

如果promise實例對象的狀態(tài)變?yōu)閞ejected泰演,

就會觸發(fā) catch() 方法指定的回調(diào)函數(shù)

如果 .then() 方法指定的回調(diào)函數(shù)在運行中拋出錯誤呻拌,也會被 catch() 方法捕獲

promise對象的錯誤具有冒泡性質(zhì),

會一直向后傳遞睦焕,直到被捕獲為止

( 也就是說錯誤總是會被下一個catch語句捕獲 )

一般來說藐握,不要在.then()方法中定義rejected狀態(tài)的回調(diào)函數(shù),

而總是使用 .catch()方法

一般總是建議垃喊,promise對象后要跟 catch()方法猾普,這樣可以處理 promise內(nèi)部發(fā)生法的錯誤,catch() 方法返回的還是promise對象本谜,

因此后面還可以接著調(diào)用 then() 方法

catch() 方法中還能再拋錯誤初家,如果 catch()方法拋出錯誤后,后面沒有catch()方法乌助,錯誤就不會被捕獲溜在,也不會傳遞到外層。

如果catch()方法拋出錯誤后他托,后面有then()方法掖肋,會照常執(zhí)行,后面有catch()方法赏参,錯誤還會被再一次捕獲

async和await:

Async返回的是Promise對象

async/await其實就是promise和generator的語法糖:

async function demo01() {

console.log(1)

return ‘demo1’;

}

demo01().then(function(a){

console.log(a)

});

輸出結(jié)果為1志笼,demo1

async用來表示函數(shù)是異步的,定義的函數(shù)會返回一個promise對象登刺,可以使用then方法添加回調(diào)函數(shù)籽腕。上列代碼中的async函數(shù)中的console.log(1)可以當(dāng)一個同步的隊列執(zhí)行,也就是說但你在定義async function的時候 里面的代碼是以同步的方式執(zhí)行纸俭,只不過async的返回是一個promise皇耗,可以用.then()的方式去執(zhí)行回調(diào),如同上述內(nèi)容揍很。若 async 定義的函數(shù)有返回值郎楼,return ‘demo1’;相當(dāng)于Promise.resolve('demo1’),沒有聲明式的 return則相當(dāng)于執(zhí)行了Promise.resolve();

await是和async一起來使用万伤,一般為:

async function demo2(){

console.log(7)

await a()

console.log(6)

}

demo2()

function a() {

console.log(‘demo2’)

}

當(dāng)他和promise一起用的話:

async myFun( ){ await new Promise(resolve=>{ }) }


總結(jié):

一般async與await同步出現(xiàn)

async返回promise對象

await出現(xiàn)在async函數(shù)內(nèi)部,單獨只用會報錯

componentDidMount() {

? ? ? ? const funSync1 = () => console.log('我是同步函數(shù)1111111')

? ? ? ? const funSync2 = () => console.log('我是同步函數(shù)2222222')

? ? ? ? const funAsync = async () => {? ? // async關(guān)鍵字呜袁,定義的函數(shù)是異步函數(shù)敌买,返回promise對象

? ? ? ? ? ? await funSync1()

? ? ? ? }

? ? ? ? funAsync().then(funSync2())

? ? ? ? console.log('bbbb')

}

// 先把兩個同步函數(shù)變成了異步,在異步函數(shù)中阶界,先執(zhí)行funSync1虹钮,后執(zhí)行funSync2

// 使用async關(guān)鍵字后,會把同步包裝成的異步函數(shù)膘融,按同步方式執(zhí)行

// 所以最后得到的輸出順序是:

// 我是同步函數(shù)1111111

// 我是同步函數(shù)2222222

// bbbb



異步和同步:

同步直接拿到結(jié)果

異步不能直接拿到結(jié)果

回調(diào)不一定用在異步芙粱,也可以用在同步

異步不一定要用到回調(diào),也可以用輪詢氧映。

異步任務(wù)不能拿到結(jié)果

異步任務(wù)完成時調(diào)用回調(diào)

結(jié)果作為參數(shù)



下面是一些例子春畔,也有面試題,主要用來輔助弄懂js執(zhí)行的順序和promise.then執(zhí)行順序:

例子1:

const p1 = () => (new Promise((resolve, reject) => {

????????????????console.log(1);

????????????????let p2 = new Promise((resolve, reject) => {

????????????????????console.log(2);

????????????????????const timeOut1 = setTimeout(() => {

????????????????????????console.log(3);

????????????????????????resolve(4); // 不執(zhí)行代碼岛都,因為p2的promise對象已經(jīng)有結(jié)果

????????????????????}, 0)

????????????????????resolve(5);

????????????????});

????????????????resolve(6);

????????????????p2.then((arg) => {

????????????????????console.log(arg);

????????????????});

????????????}));

????????????const timeOut2 = setTimeout(() => {

????????????????console.log(8);

????????????????const p3 = new Promise(reject => {

????????????????????reject(9);

????????????????}).then(res => {

????????????????????console.log(res)

????????????????})

????????????}, 0)

????????????p1().then((arg) => {

????????????????console.log(arg);

????????????});

????????????console.log(10);

????????????// 打印結(jié)果:1,2,10,5,6,8,9,3

????????????第一輪

????????????宏任務(wù):timeOut2律姨,timeOut1

????????????微任務(wù):p2.then,p1.then(本輪結(jié)束前清空)

????????????打印:1臼疫,2择份,10,5多矮,6

????????????第二輪

????????????宏任務(wù):timeOut2缓淹,timeOut1

????????????微任務(wù):p3.then(本輪結(jié)束前清空)

????????????打印:8塔逃,9

????????????第三輪

????????????宏任務(wù):timeOut1

????????????微任務(wù):

????????????打友逗:3

例子2:

console.log('script start');

????????????// Promise.resolve('foo') 等價于 new Promise(resolve => resolve('foo')),所以會先讓同步任務(wù)先執(zhí)行湾盗,所以這里打印script start伏蚊,然后是script end。

????????????setTimeout(function () {

????????????????console.log('setTimeout---0');

????????????}, 0);

????????????setTimeout(function () {

????????????????console.log('setTimeout---200');

????????????????setTimeout(function () {

????????????????????console.log('inner-setTimeout---0');

????????????????});

????????????????Promise.resolve().then(function () {

????????????????????console.log('promise5');

????????????????});

????????????}, 200);

????????????Promise.resolve().then(function () {

????????????????console.log('promise1');

????????????????// 每個new promise內(nèi)有resolve會先優(yōu)先于.then執(zhí)行格粪,所以這里會先打印promise1躏吊,然后打印promise3,再打印promise2(個人理解帐萎,源碼類似這個邏輯)

????????????}).then(function () {

????????????????console.log('promise2');

????????????});

????????????Promise.resolve().then(function () {

????????????????console.log('promise3');

????????????});

????????????console.log('script end');

????????????// 執(zhí)行結(jié)果: script start矿微,script end五续,promise1,promise3,promise2励负,setTimeout---0,setTimeout---200,promise5,inner-setTimeout---0

例子3:

const promise = new Promise((resolve, reject) => {

????????????????console.log(1)

????????????????????setTimeout(() => {

????????????????????????console.log('once')

????????????????????????resolve('success')

????????????????????}, 1000)

????????????})

????????????// 1打印后舰攒,promise.then剛開始沒有執(zhí)行,因為promise對象還沒有結(jié)果悔醋,也就是狀態(tài)還是pendding摩窃,等到執(zhí)行setTimeout后有了狀態(tài)后才執(zhí)行promise.then

????????????// 另外因為狀態(tài)改變后不會再改變,所以兩個promise.then打印都是一樣結(jié)果

????????????promise.then((res) => {

????????????????console.log(res)

????????????????})

????????????promise.then((res) => {

????????????????console.log(res)

????????????})

????????????// 執(zhí)行結(jié)果:1芬骄,once猾愿,success,success

例子4:

let thenable = {

????????????????then: function(resolve, reject) {

????????????????????resolve(6);

????????????????}

????????????};

????????????// let p = Promise.resolve();

????????????let p = new Promise((resolve, reject) =>{

????????????????resolve(7)

????????????});

????????????setTimeout(()=>{

????????????????console.log(1)

????????????},0)

????????????// Promise.resolve()方法返回一個新的 Promise 對象账阻,狀態(tài)為resolved匪蟀。Promise.resolve().then就是微任務(wù),所有比setTimeout提前打印

????????????// promise.resolve()方法:參數(shù)不是具有then方法的對象宰僧,或根本就不是對象(也就是2,5观挎,4)和參數(shù)是一個promise對象(也就是7)琴儿,他們的優(yōu)先級高于參數(shù)是一個thenable對象


????????????Promise.resolve().then(()=>{

????????????????console.log(2)

????????????})

????????????Promise.resolve(thenable).then((value)=>{

????????????????console.log(value)

????????????})

????????????Promise.resolve(p).then((v)=>{

????????????????console.log(v)

????????????})

????????????Promise.resolve('5').then(()=>{

????????????????console.log('5')

????????????})

????????????Promise.resolve().then(()=>{

????????????????console.log(4)

????????????})

????????????console.log(3)

????????????//執(zhí)行結(jié)果: 3,2嘁捷,7,5造成,4,6雄嚣,1

例子5:

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)

????????????????})

????????????}))

????????????console.log(4)

????????????// 這道題沒什么特殊晒屎,主要指出要注意new Promise有沒有被放在函數(shù)里,如果放在函數(shù)里缓升,是要等到被調(diào)用(first())才會執(zhí)行鼓鲁,而不是new promise就直接執(zhí)行了

????????????first().then((arg) => {

????????????????console.log(arg)

????????????})


????????????// 執(zhí)行結(jié)果: 4,3港谊,7骇吭,1,2歧寺,5

????????????// 第一輪

????????????// 宏任務(wù):setTimeout

????????????// 微任務(wù):p.then,first.then

????????????// 打釉镎:4,3斜筐,7龙致,1,2

????????????// 第二輪

????????????// 宏任務(wù):setTimeout

????????????// 微任務(wù):

????????????// 打忧炅础:5

例子6:

setTimeout(() => {

????????????????console.log("0")

????????????}, 0)

????????????new Promise((resolve,reject)=>{ // promise1

????????????????console.log("1")

????????????????resolve() // 第一個resolve

????????????}).then(()=>{? ? ? ?

????????????????console.log("2")

????????????????new Promise((resolve,reject)=>{ // promise2

????????????????????console.log("3")

????????????????????resolve() // 第二個resolve

????????????????}).then(()=>{? ? ?

????????????????????console.log("4")

????????????????}).then(()=>{? ? ?

????????????????????console.log("5")

????????????????})

????????????}).then(()=>{?

????????????????console.log("6")

????????????})


????????????new Promise((resolve,reject)=>{ // promise3

????????????????console.log("7")

????????????????resolve() // 第三個resolve

????????????}).then(()=>{? ? ? ?

????????????????console.log("8")

????????????})

????????????// 首先執(zhí)行兩個new Promise打印1目代,7,然后是resolve1和resolve3進入隊列。執(zhí)行resolve1像啼,打印2俘闯,3,resolve2進入隊列(這個時候?qū)τ趐romise1的第一個then來說忽冻,已經(jīng)有了fullfilled狀態(tài)真朗,所以promie1第二個then也進入隊列),

????????????// 所以打印8僧诚,4遮婶, 6,5湖笨,最后打印0

????????????// 執(zhí)行結(jié)果:1,7,2,3,8,4,? 6,5,(這一步要注意旗扑,promise1.then是先進入任務(wù)隊列,不是5慈省,6),0

例子7:

async function async1() {

????????????console.log('async1 start')

????????????await async2()? // 相當(dāng)于async2().then(() => {})臀防,所以下面這個'async1 end'是先被放到微任務(wù)隊列

????????????console.log('async1 end')

????????}

????????async function async2() {

????????????console.log('async2')

????????}

????????console.log('script start')

????????setTimeout(() => {

????????????console.log('setTimeout')

????????}, 0)

????????async1()


????????new Promise(function (resolve) {

????????????console.log('promise1')

????????????resolve()

????????}).then(function () {

????????????console.log('promise2')

????????})

????????console.log('script end')

????????// 這里比較容易弄錯的是async2,async1 end的位置边败。async1 start之后為什么會馬上執(zhí)行async2袱衷,應(yīng)該是這個await的作用(變異步為同步,必須等待await后的函數(shù)先執(zhí)行)

????????// 然后就是await async2()相當(dāng)于async2().then(() => {})笑窜,所以下面這個'async1 end'是先被放到微任務(wù)隊列致燥,Promise.then后面放入微任務(wù)隊列,所以async1 end比promise2先執(zhí)行排截。


????????// 答案依次:script start ==> async1 start ==> async2 ==> promise1 ==>

????????// script end ==> async1 end ==> promise2 ==> setTimeOut

例子8:

// async用來表示函數(shù)是異步的嫌蚤,定義的函數(shù)會返回一個promise對象,可以使用then方法添加回調(diào)函數(shù)断傲。

????????// 也就是說你在定義async function的時候 里面的代碼是以同步的方式執(zhí)行脱吱,只不過async的返回是一個promise,可以用.then()的方式去執(zhí)行回认罩。

????????// 若 async 定義的函數(shù)有返回值急凰,return ‘demo1’;相當(dāng)于Promise.resolve('demo1’),沒有聲明式的 return則相當(dāng)于執(zhí)行了Promise.resolve();

????????async function demo01() {

????????????console.log(1)

????????????return 'demo1';

????????}

????????console.log('0')

????????demo01().then(function(a){

????????????console.log(a)

????????});

????????console.log('8')

????????async function demo2(){

????????????console.log(7)

????????????await a()

????????????console.log(6)

????????}

????????demo2()

????????let promise = new Promise(function(resolve, reject){

????????????resolve(5)

????????????console.log(3)

????????????setTimeout(function(){console.log(4)})

????????})

????????console.log(2)

????????promise.then(function(a){

????????????console.log(a)

????????})

????????function a(){

????????????console.log('demo2')

????????}

????????// 0,1猜年,8抡锈,7,demo2,3,2,demo1,6,5,4

例子9:有點難

const p1 = Promise.resolve();

????????????let p3;

????????????const p2 = new Promise(function(resolve, reject){

????????????// 依賴p1的狀態(tài),比p1延遲了兩個tick即ticke-3執(zhí)行then

????????????p3 = new Promise(res => res(p1));

????????????// 等價于p1.then(tick1).then(tick2).then(logp3)

????????????p3.then(() => {

????????????????// tick-3

????????????????console.log('p3')

????????????????resolve('ok');

????????????})

????????????});

????????????p1.then(() => {

????????????// tick-1

????????????console.log('p1-1')

????????????}).then(() => {

????????????// tick-2

????????????console.log('p1-2')

????????????}).then(() => {

????????????// tick-3

????????????console.log('p1-3')

????????????})

????????????p2.then(function(data) {

????????????// p2在tick-3時resolve則本函數(shù)在tick-4執(zhí)行

????????????console.log('p2-1')

????????????}).then(function(data) {

????????????// tick-5

????????????console.log('p2-2')

????????????}).then(function(data) {

????????????// tick-6

????????????console.log('p2-3')

????????????})

????????????p3.then(function(data) {

????????????// 與p2內(nèi)部的then在同一時刻即tick-3

????????????console.log('p3-1')

????????????}).then(function(data) {

????????????// tick-4

????????????console.log('p3-2')

????????????}).then(function(data) {

????????????// tick-5

????????????console.log('p3-3')

????????????})

根據(jù)不同的tick整理順序可得:

// tick-1: p1-1

????????????// tick-2: p1-2

????????????// tick-3: p3,p3-1,p1-3 【由于p3先入棧tick3任務(wù)故在p1-3之前】

????????????// tick-4: p2-1,p3-2

????????????// tick-5: p2-2,p3-3

????????????// tick-5: p2-3

如果把p3部分的代碼轉(zhuǎn)換下是等效于下面這段的

const p2 = new Promise(function(resolve, reject){

????????????// 依賴p1的狀態(tài),比p1延遲了兩個tick即ticke-3執(zhí)行then

????????????const noop = () => void 0;

????????????p3 = p1.then(noop).then(noop);

????????????// 等價于p1.then(tick1).then(tick2).then(logp3)

????????????p3.then(() => {

????????????????// tick-3

????????????????console.log('p3')

????????????????resolve('ok');

????????????})

????????????});

例子10:

// 下面是兩個例子

// 例子1:

const p1 = new Promise(function (resolve, reject) {

????????????setTimeout(() => reject(new Error('fail')), 3000)

????????})

????????const p2 = new Promise(function (resolve, reject) {

????????????setTimeout(() => {

????????????????console.log('p2')

????????????????resolve(p1)

????????????}, 1000)

????????})

????????p2

????????.then(result => console.log(result))

????????.catch(error => console.log(error))

????????// 打印結(jié)果:p2,Error:fail

????????// 上面代碼中乔外,p1是一個 Promise床三,3 秒之后變?yōu)閞ejected。p2的狀態(tài)在 1 秒之后改變杨幼,resolve方法返回的是p1撇簿。由于p2返回的是另一個 Promise聂渊,

????????// 導(dǎo)致p2自己的狀態(tài)無效了,由p1的狀態(tài)決定p2的狀態(tài)四瘫。所以汉嗽,后面的then語句都變成針對后者(p1)。又過了 2 秒找蜜,p1變?yōu)閞ejected饼暑,導(dǎo)致觸發(fā)catch方法指定的回調(diào)函數(shù)。

????????// 注意洗做,調(diào)用resolve或reject并不會終結(jié) Promise 的參數(shù)函數(shù)的執(zhí)行弓叛。

new Promise((resolve, reject) => {?// 例子2:

????????????resolve(1);

????????????console.log(2);

????????}).then(r => {

????????????console.log(r);

????????});

????????// 2

????????// 1

????????// 上面代碼中,調(diào)用resolve(1)以后诚纸,后面的console.log(2)還是會執(zhí)行撰筷,并且會首先打印出來。這是因為立即 resolved 的 Promise 是在本輪事件循環(huán)的末尾執(zhí)行畦徘,

????????// 總是晚于本輪循環(huán)的同步任務(wù)毕籽。

????????// 一般來說,調(diào)用resolve或reject以后井辆,Promise 的使命就完成了影钉,后繼操作應(yīng)該放到then方法里面,而不應(yīng)該直接寫在resolve或reject的后面掘剪。

????????// 所以,最好在它們前面加上return語句奈虾,這樣就不會有意外夺谁。

????????new Promise((resolve, reject) => {

????????????return resolve(1);

????????????// 后面的語句不會執(zhí)行

????????????console.log(2);

????????})

例子11:

const getJSON = (num)=>(new Promise((resolve,reject)=>resolve(num)))

????????getJSON(1).then(function(json) {

????????????console.log(json)

????????????return json+1;

????????}).then(function(post) {

????????????console.log(post)

????????});

????????// 打印:1肉微,2

????????const getJSON = (num)=>(new Promise((resolve,reject)=>resolve(num)))

????????getJSON(1).then(function(post) {

????????????return getJSON(2);

????????}).then(function (comments) {

????????????console.log("resolved: ", comments);

????????}, function (err){

????????????console.log("rejected: ", err);

????????});

????????// 打迂遗浮:resolved:? 2

例子12:重要

promise.then內(nèi)包含prmise.then,但是內(nèi)部這個promise前面沒有return的情況

new Promise((resolve, reject) => {

????????????console.log("promise")

????????????resolve()

????????})

????????.then(() => {???// 執(zhí)行.then的時候生成一個promise是給最后一個.then的

????????????console.log("then1")

????????????new Promise((resolve, reject) => {

????????????????console.log("then1promise")

????????????????resolve()

????????????})

????????????.then(() => {// 執(zhí)行這個.then的時候碉纳,生成的promise是下面一個then的

????????????????console.log("then1then1")

????????????????setTimeout(()=>{

????????????????????console.log('setTimeout')

????????????????},0)

????????????})

????????????.then(() => {

????????????????console.log("then1then2")

????????????})

????????})

????????.then((res) => {

????????// 這個

????????????console.log("then2",res)

????????})

????????// 執(zhí)行結(jié)果:promise勿负,then1,then1promise劳曹,then1then1奴愉,then2 undefined,then1then2,setTimeout

例子13:重要

promise.then內(nèi)包含prmise.then铁孵,但是內(nèi)部這個promise前面有return的情況

new Promise((resolve, reject) => {

????????????console.log("promise")

????????????resolve()

????????})

????????.then(() => {???// 執(zhí)行.then的時候生成一個promise是給最后一個.then的

????????????console.log("then1")

????????????return new Promise((resolve, reject) => {

????????????????console.log("then1promise")

????????????????resolve()

????????????})

????????????.then(() => {// 執(zhí)行這個.then的時候锭硼,生成的promise是下面一個then的

????????????????console.log("then1then1")

????????????????setTimeout(()=>{

????????????????????console.log('setTimeout')

????????????????},0)

????????????})

????????????.then(() => {

????????????????console.log("then1then2")

????????????})

????????})

????????.then((res) => {

????????// 這個

????????????console.log("then2",res)

????????})

????????// 注意:.then1函數(shù)體有了return返回值,是一個Promise對象蜕劝,而且是then1then2執(zhí)行完返回的匿名Promise對象檀头。所以只有等這個Promise對象resolve了之后轰异,才會執(zhí)行then2回調(diào)函數(shù)體的邏輯,所以’then2’最后才會打印暑始。

????????// 執(zhí)行結(jié)果:promise搭独,then1,then1promise廊镜,then1then1牙肝,then1then2,then2 undefined,setTimeout

關(guān)于例子12和例子13期升,說說自己的一點觀點:內(nèi)部promise在resolve后立即執(zhí)行后面的then(其他不是包含promise也是這樣)惊奇,然后會跳出來執(zhí)行外部promise的一個then,而不是繼續(xù)執(zhí)行內(nèi)部promise的下一個then播赁。如果有return颂郎,情況就不一樣了。

例子14:難容为,不懂乓序,待解釋

1. 當(dāng)Promise對象作為resolve的參數(shù)時

const p = Promise.resolve();

????????const p1 = Promise.resolve(p); //就是p

????????const p2 = new Promise(res => res(p)); //新建一個對象,對象狀態(tài)依賴p

????????// res(p)可以看作 await p1; await resolve();

????????// 或者p.then(data => getData()).then(() => p2.resolve())

????????// 首先坎背;p1 === p; p2!===p

????????// 那么替劈,p1是一個fulfilled狀態(tài)的對象;p2狀態(tài)需要運行后求得

????????console.log(p === p1); // true

????????console.log(p === p2); // false

????????p1.then(() => {

????????????console.log('p1-1');

????????}).then(() => {

????????????console.log('p1-2');

????????}).then(() => {

????????????console.log('p1-3');

????????})

????????p2.then(() => { //p-2.resolve之后才能調(diào)用回調(diào)函數(shù)

????????????console.log('p2-1');

????????}).then(() => {

????????????console.log('p2-2');

????????}).then(() => {

????????????console.log('p2-3');

????????})

????????p.then(() => {

????????????console.log('p-1');

????????}).then(() => {

????????????console.log('p-2');

????????}).then(() => {

????????????console.log('p-3');

????????})


????????//? 運行結(jié)果

????????// getData()

????????// p1-1

????????// p-1

????????// 前面兩個打印因為本身狀態(tài)已經(jīng)resolve了得滤,所以直接出結(jié)果

????????// resolve()

????????// p1-2

????????// p-2

????????// p2-1

????????// p1-3

????????// p-3

????????// p2-2

????????// p2-3

????????// 后面打印p2-1是等到p運行resolve后才開始打印

例子15:難

2. 當(dāng)Promise的resolve方法在另一個Promise對象的then方法中運行時陨献,變異步眨业;

例子12和例子13類似:p1要等resolve才能執(zhí)行后面的then,所以p3先執(zhí)行了龄捡。只要有resolve慷暂,就會先執(zhí)行屬于那個resolve的then聘殖,然后執(zhí)行另外一個promise的resolve的then,最后才會繼續(xù)第一個resolve接下去的then

let p3;

????????p1 = new Promise(resolve => {

????????????p3 = new Promise(res => res());

????????????p3.then(() => {

????????????????console.log('p3')

????????????????resolve(); // resolve()方法用在then方法中行瑞,變?yōu)楫惒綀?zhí)行

????????????})

????????})

????????p1.then(() => {

????????????console.log('p1-1');

????????}).then(() => {

????????????console.log('p1-2');

????????})


????????p3.then(() => {

????????????console.log('p3-1')

????????}).then(() => {

????????????console.log('p3-2')

????????})

????????// 執(zhí)行結(jié)果:p3,p3-1,p1-1,p3-2,p1-2

例子16:

new Promise((r,rj) => {

????????????console.log('外p');

????????????r();

????????}).then(() => {

????????????console.log('外then1');

????????????new Promise(((r,rj) => {

????????????????console.log('內(nèi)p');

????????????????r();

????????????})).then(() => {

????????????????console.log('內(nèi)then1');

????????????????return new Promise((r, rj) => {r();});

????????????}).then(() => {

????????????????console.log('內(nèi)then2');

????????????});

????????}).then(() => {

????????????console.log('外then2');

????????}).then(() => {

????????????console.log('外then3');

????????}).then(() => {

????????????console.log('外then4');

????????});

// ?????return new Promise((r, rj) => {r();})? 等同于

// ? ? ?return new Promise((r, rj) => {r();}).then(()=>{console.log(1)}).then(()=>{console.log(2)}).then(()=>{console.log(3)});

????????// 執(zhí)行結(jié)果:外p奸腺,外then1,內(nèi)p血久,內(nèi)then1洋机, 外then2,外then3洋魂,外then4绷旗,內(nèi)then2喜鼓,

例子17:------

// 例子1:
// await 不過是generator和promise結(jié)合后的一種語法糖

????????// await 會生成一個 Promise ,以其后表達式的值 resolve 這個 Promise(類似 Promise.resolve())衔肢,并在它的 then 回調(diào)里執(zhí)行 await 返回之后的一切庄岖,同時結(jié)束程序的執(zhí)行。

????????function doA1(){?

????????????new Promise( function (resolve) {?

????????????????console.log(11);?

????????????????resolve();?

????????????}).then(o=>{?

????????????console.log(12);?

????????????}).then(o=>{?

????????????console.log(13);?

????????????}).then(o=>{?

????????????console.log(14);?

????????????})?

????????}?


????????await doA1();?

????????console.log(2);

????????//執(zhí)行結(jié)果順序為 11 12 2 13 14

????????// 按代碼執(zhí)行順序角骤,首先初始事件循環(huán):

????????// 1.Promise 的 executor 參數(shù)是立即執(zhí)行的隅忿,所以馬上打印 11。

????????// 2.因為馬上 resolve 了邦尊,后面跟著 then 故 promise 進入微事件隊列中背桐,繼續(xù)執(zhí)行其它平臺代碼。

????????// 3.await 因為跟了一個非 Promise 的值所以會自動包上一層 Promise.resolve蝉揍,即無論如何都會至少等一個微事件周期链峭。所以得到的 undefined 也進入微事件隊列。

????????// await 阻塞了又沾,本事件循環(huán)準備結(jié)束,開始清微事件隊列

????????// 1.先是前面 11 得到的 promise杖刷,處理 then 回調(diào)打印 12滑燃,后面的 promise 繼續(xù)入微事件隊列表窘。

????????// 2.接著是 await 得到 undefined蚊丐,因為沒有賦值麦备,被丟棄凛篙。

????????// 3.await 得到了值呛梆,不再阻塞填物,繼續(xù)往下執(zhí)行打印 2。

????????// 4.await 后的平臺代碼執(zhí)行完畢升薯,微事件隊列中還有 12 得到 promise涎劈。

????????// 5.重復(fù)上邊過程打印 13 和 14

????????// 6.微事件隊列已清空阅茶,本事件循環(huán)結(jié)束脸哀。

// 例子2:

????????// 返回了 Promise 那么 await 就會等這個 Promise 都 resolve 了才會繼續(xù)往下執(zhí)行企蹭。

????????function doA1(){

????????????return new Promise( function (resolve) {

????????????????console.log(11);

????????????????resolve();

????????????}).then(o=>{

????????????console.log(12);

????????????}).then(o=>{

????????????console.log(13);

????????????}).then(o=>{

????????????console.log(14);

????????????})

????????}

????????await doA1();

????????console.log(2);

????????//執(zhí)行結(jié)果順序為 11 12 13 14 2

例子18:難

new Promise((r,rj) => {

????????????console.log('外p');

????????????r();

????????}).then(() => {

????????????console.log('外then1');

????????????new Promise(((r,rj) => {

????????????????console.log('內(nèi)p');

????????????????r();

????????????})).then(() => {

????????????????console.log('內(nèi)then1');

????????????????return new Promise((r, rj) => {r();});

????????????}).then(() => {

????????????????console.log('內(nèi)then2');

????????????});

????????}).then(() => {

????????????console.log('外then2');

????????}).then(() => {

????????????console.log('外then3');

????????}).then(() => {

????????????console.log('外then4');

????????});

// ?????return new Promise((r, rj) => {r();})? 等同于

// ? ? ?return new Promise((r, rj) => {r();}).then(()=>{console.log(1)}).then(()=>{console.log(2)}).then(()=>{console.log(3)});

????????// 執(zhí)行結(jié)果:外p谅摄,外then1送漠,內(nèi)p闽寡,內(nèi)then1爷狈, 外then2,外then3思币,外then4谷饿,內(nèi)then2博投,

例子19:

const p1 = new Promise( (resolve,reject) => {

????????????setTimeout(() => {

????????????????reject(new Error('fail'))

????????????????console.log('3s')? // console.log語句仍然會執(zhí)行毅哗,并且在reject()異步函數(shù) 前執(zhí)行

????????????},3000)

????????})

????????const p2 = new Promise( (resolve,reject) => {

????????????setTimeout( () => {

????????????????return resolve(p1)? // 一般都在這里加return,這樣后面的代碼就不會執(zhí)行叉跛,防止意外?昀濉酥艳!

????????????????console.log('1s')

????????????}, 1000 )

????????})

????????p2.then(res => console.log(res))? ? // 并沒有執(zhí)行

????????.catch(error => console.log(error))

????????// 打印結(jié)果:3s充石,Error:fail

????????// 注意: p2.then(res => console.log(....))并沒有執(zhí)行霞玄,因為p2的狀態(tài)變成了p1的狀態(tài),是rejected

????????// p2.then(res => console.log(res,'fulfilled'), res => console.log(res,'rejected'))

????????// 實際執(zhí)行的是上面的 第二個回調(diào)函數(shù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末惰爬,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子撕瞧,更是在濱河造成了極大的恐慌丛版,老刑警劉巖页畦,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件豫缨,死亡現(xiàn)場離奇詭異州胳,居然都是意外死亡记焊,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門碗硬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弛说,“玉大人木人,你說我怎么就攤上這事冀偶〗” “怎么了客年?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵司恳,是天一觀的道長榔至。 經(jīng)常有香客問我唧取,道長枫弟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮韩容,結(jié)果婚禮上群凶,老公的妹妹穿的比我還像新娘。我一直安慰自己力穗,他們只是感情好当窗,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布崖面。 她就那樣靜靜地躺著嘶朱,像睡著了一般疏遏。 火紅的嫁衣襯著肌膚如雪财异。 梳的紋絲不亂的頭發(fā)上戳寸,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天疫鹊,我揣著相機與錄音拆吆,去河邊找鬼枣耀。 笑死捞奕,一個胖子當(dāng)著我的面吹牛颅围,可吹牛的內(nèi)容都是我干的院促。 我是一名探鬼主播一疯,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼盏浙!你這毒婦竟也來了竹海?” 一聲冷哼從身側(cè)響起丐黄,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤灌闺,失蹤者是張志新(化名)和其女友劉穎桂对,沒想到半個月后蕉斜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體机错,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡毡熏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年痢法,在試婚紗的時候發(fā)現(xiàn)自己被綠了财搁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尖奔。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡淹禾,死狀恐怖铃岔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卖丸,我是刑警寧澤稍浆,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布恐仑,位于F島的核電站裳仆,受9級特大地震影響孤钦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜静袖,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一队橙、第九天 我趴在偏房一處隱蔽的房頂上張望捐康。 院中可真熱鬧庸蔼,春花似錦解总、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽刻盐。三九已至,卻和暖如春劳翰,著一層夾襖步出監(jiān)牢的瞬間敦锌,已是汗流浹背佳簸。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工疯特, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人邻吞。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓梢褐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鸣剪。 傳聞我的和親對象是個殘疾皇子江滨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容