日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

原来你是这样的Promise

發(fā)布時間:2023/12/20 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 原来你是这样的Promise 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1. Promise簡介

promise是異步編程的一種解決方案,它出現(xiàn)的初衷是為了解決回調(diào)地獄的問題。

打個比方,我需要:

--(延遲1s)--> 輸出1 --(延遲2s)--> 輸出2 --(延遲3s)--> 輸出3

通常寫法:

setTimeout(()=> {console.log('1');setTimeout(()=> {console.log('2');setTimeout(()=> {console.log('3'); }, 3000)}, 2000) }, 1000)

這樣的多重的嵌套的回調(diào)被稱為回調(diào)地獄,這樣的代碼可讀性很差,不利于理解。

如果用promise的話畫風(fēng)一轉(zhuǎn)

function delay(time, num) {return new Promise((res, rej)=> {setTimeout(()=> {console.log(num);res();}, time*1000)}); } delay(1, 1).then(()=> {return delay(2, 2); }).then(()=> {delay(3, 3); }) 使用了promise的鏈?zhǔn)秸{(diào)用,代碼結(jié)構(gòu)更清晰。

是不是很棒?那還不趕快get起來~

2. Promise的使用

調(diào)用方式如下:

new Promise((resolve, reject)=> {if('some option') {resolve('some value');} else {reject('some error');} }).then(val=> {// ... },error=> {// ... } )

Promise構(gòu)造函數(shù)接收一個函數(shù)型參數(shù)fn,fn有兩個參數(shù),分別是:resolve、reject,Promise還有一個Promise.prototype.then方法,該方法接收兩個參數(shù),分別是成功的回調(diào)函數(shù)succ和失敗的回調(diào)函數(shù)error。

在fn中調(diào)用resolve會觸發(fā)then中的succ回調(diào),調(diào)用reject會觸發(fā)error回調(diào)。

2.1 參數(shù)傳遞

  • 在fn內(nèi)部調(diào)用resolve/reject傳入的參數(shù)會作為相應(yīng)參數(shù)傳入相應(yīng)的回調(diào)函數(shù) new Promise((res, rej)=> {res('happy') }).then(val=> {console.log(val); // happy });new Promise((res, rej)=> {rej('error!'); }).then(val=> {}, err=> {console.log(err); // error! });
  • 鏈?zhǔn)秸{(diào)用時若上一級沒有傳遞值則默認(rèn)為undefined new Promise((res, rej)=> {res('a'); }).then(val=> {return 'b' }).then(val=> {console.log(val); // 'b' }).then((val)=> {console.log(val); // 'undefined' });
  • 若上一級的then中傳遞的并非函數(shù),則忽略該級 new Promise((res, rej)=> {res('a'); }).then(val=> {return 'b'; }).then(val=> {console.log(val); // 'b'return 'c'; }).then({ // 并非函數(shù)name: 'lan' }).then((val)=> {console.log(val); // 'c' });

2.2 參數(shù)傳遞例題

let doSomething = function() {return new Promise((resolve, reject) => {resolve('返回值');}); };let doSomethingElse = function() {return '新的值'; }doSomething().then(function () {return doSomethingElse(); }).then(resp => {console.warn(resp);console.warn('1 =========<'); });doSomething().then(function () {doSomethingElse(); }).then(resp => {console.warn(resp);console.warn('2 =========<'); });doSomething().then(doSomethingElse()).then(resp => {console.warn(resp);console.warn('3 =========<'); });doSomething().then(doSomethingElse).then(resp => {console.warn(resp);console.warn('4 =========<'); });

結(jié)合上面的講解想一想會輸出什么?(答案及解析)

3. Promise.prototype.then

當(dāng)Promise中的狀態(tài)(pending?--->?resolved?or?rejected)發(fā)生變化時才會執(zhí)行then方法。

  • 調(diào)用then返回的依舊是一個Promise實例 ( 所以才可以鏈?zhǔn)秸{(diào)用... )
new Promise((res, rej)=> {res('a'); }).then(val=> {return 'b'; });// 等同于 new Promise((res, rej)=> {res('a'); }).then(val=> {return new Promise((res, rej)=> {res('b');}); });
  • then中的回調(diào)總會異步執(zhí)行
new Promise((res, rej)=> {console.log('a');res(''); }).then(()=> {console.log('b'); }); console.log('c'); // a c b
  • 如果你不在Promise的參數(shù)函數(shù)中調(diào)用resolve或者reject那么then方法永遠(yuǎn)不會被觸發(fā)
new Promise((res, rej)=> {console.log('a'); }).then(()=> {console.log('b'); }); console.log('c'); // a c

4. Promise的靜態(tài)方法

Promise還有四個靜態(tài)方法,分別是resolve、reject、all、race,下面我們一一介紹一下。

4.1 Promise.resolve()

除了通過new Promise()的方式,我們還有兩種創(chuàng)建Promise對象的方法,Promise.resolve()相當(dāng)于創(chuàng)建了一個立即resolve的對象。如下兩段代碼作用相同:

Promise.resolve('a');new Promise((res, rej)=> {res('a'); });

當(dāng)然根據(jù)傳入的參數(shù)不同,Promise.resolve()也會做出不同的操作。

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

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

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

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

let thenable = {then: function(resolve, reject) {resolve(42);} };

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

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

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

  • 不帶有任何參數(shù)

Promise.resolve方法允許調(diào)用時不帶參數(shù),直接返回一個resolved狀態(tài)的 Promise 對象。

值得注意的一點是該靜態(tài)方法是在本次事件輪詢結(jié)束前調(diào)用,而不是在下一次事件輪詢開始時調(diào)用。關(guān)于事件輪詢可以看這里——>JavaScript 運行機(jī)制詳解:再談Event Loop

4.2 Promise.reject()

和Promise.resolve()類似,只不過一個是觸發(fā)成功的回調(diào),一個是觸發(fā)失敗的回調(diào)

4.3 Promise.all()

Promise的all方法提供了并行執(zhí)行異步操作的能力,并且在所有異步操作執(zhí)行完后才執(zhí)行回調(diào)。

function asyncFun1() {return new Promise((res, rej)=> {setTimeout(()=> { res('a');}, 1000);}); } function asyncFun2() {return new Promise((res, rej)=> {setTimeout(()=> { res('b');}, 1000);}); } function asyncFun3() {return new Promise((res, rej)=> {setTimeout(()=> { res('c');}, 1000);}); } Promise.all([asyncFun1(), asyncFun2(), asyncFun3()]).then((val)=> {console.log(val); }); Promise.all([asyncFun1(), asyncFun2(), asyncFun3()]).then((val)=> {console.log(val); // ['a', 'b', 'c'] });

用Promise.all來執(zhí)行,all接收一個數(shù)組參數(shù),里面的值最終都算返回Promise對象。這樣,三個異步操作的并行執(zhí)行的,等到它們都執(zhí)行完后才會進(jìn)到then里面。有了all,你就可以并行執(zhí)行多個異步操作,并且在一個回調(diào)中處理所有的返回數(shù)據(jù)。

適用場景:打開網(wǎng)頁時,預(yù)先加載需要用到的各種資源如圖片、flash以及各種靜態(tài)文件。所有的都加載完后,我們再進(jìn)行頁面的初始化。

4.4 Promise.race()

race()和all相反,all()是數(shù)組中所有Promise都執(zhí)行完畢就執(zhí)行then,而race()是一旦有一個Promise執(zhí)行完畢就會執(zhí)行then(),用上面的三個Promise返回值函數(shù)舉例

Promise.race([asyncFun1(), asyncFun2(), asyncFun3()]).then((val)=> {console.log(val); // a });

5. 鏈?zhǔn)秸{(diào)用經(jīng)典例題

看了這么多關(guān)于Promise的知識,我們來做一道題鞏固一下。

寫一個類Man實現(xiàn)以下鏈?zhǔn)秸{(diào)用調(diào)用方式: new Man('lan').sleep(3).eat('apple').sleep(5).eat('banana');
打印:
'hello, lan' -(等待3s)--> 'lan eat apple' -(等待5s)--> 'lan eat banana'

思路:

  • 在原型方法中返回this達(dá)到鏈?zhǔn)秸{(diào)用的目的
  • 等待3s執(zhí)行的效果可以用Promise & then實現(xiàn)

具體實現(xiàn)如下:

class Man {constructor(name) {this.name = name;this.sayName();this.rope = Promise.resolve(); // 定義全局Promise作鏈?zhǔn)秸{(diào)用 }sayName() {console.log(`hello, ${this.name}`);}sleep(time) {this.rope = this.rope.then(()=> {return new Promise((res, rej)=> {setTimeout(()=> {res();}, time*1000);});});return this;}eat(food) {this.rope = this.rope.then(()=> {console.log(`${this.name} eat ${food}`); });return this;} }new Man('lan').sleep(3).eat('apple').sleep(5).eat('banana');

ok!不知道你有沒有看懂呢?如果能完全理解代碼那你的Promise可以通關(guān)了,順便來個小思考,下面這種寫法可以嗎?和上面相比有什么區(qū)別?:

class Man1345 {constructor(name) {this.name = name;this.sayName(); }sayName() {console.log(`hello, ${this.name}`);}sleep(time) { this.rope = new Promise((res, rej)=> {setTimeout(()=> {res();}, time*1000);}); return this;}eat(food) {this.rope = this.rope.then(()=> { console.log(`${this.name} eat ${food}`); });return this;} }new Man('lan').sleep(3).eat('apple').sleep(5).eat('banana');

簡單的說,第二段代碼的執(zhí)行結(jié)果是

'hello, lan' -(等待3s)--> 'lan eat apple' ---> 'lan eat banana'

為什么會出現(xiàn)這種差別? 因為第二段代碼每一次調(diào)用sleep都會new一個新的Promise對象,調(diào)用了兩次sleep就new了兩個Promise對象。這兩個對象是異步并行執(zhí)行,會造成兩句eat同時顯示。

和以下情況類似

var time1 = setTimeout(()=> {console.log('a'); }, 1000) var time2 = setTimeout(()=> {console.log('b'); }, 1000) // 同時輸出 a b

抽象一點的講解是:

// 第一段正確的代碼的執(zhí)行為 var p1 = new Promise().then('停頓3s').then('打印食物').then('停頓5s').then('打印食物');// 第二段代碼的執(zhí)行行為,p1、p2異步并行執(zhí)行 var p1 = new Promise().then('停頓3s').then('打印食物'); var p2 = new Promise().then('停頓5s').then('打印食物'); 總結(jié)

Promise的經(jīng)常用到的地方:

  • 擺脫回調(diào)地獄
  • 多個異步任務(wù)同步

Promise是我們的好幫手,不過還有另一種方法也可以做到,那就是async&await,可以多多了解一下。

參考資料

ECMAScript 6 入門

通俗淺顯的理解Promise中的then

大白話講解promise

轉(zhuǎn)載于:https://www.cnblogs.com/wind-lanyan/p/8849643.html

總結(jié)

以上是生活随笔為你收集整理的原来你是这样的Promise的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。