人妻精品在线观看一区二区三区,蜜臀av精品一区二区三区网站,中文一区二区三区亚洲欧美,熟女人妇精品一区二区,人妻av在线观看视频,欧美日韩国产三级精品网站,黄色免费网站直接进入,超碰公开福利正在播放,国产毛片乡下农村妇女毛片

一文帶你輕松掌握Promise

來源:php中文網(wǎng) | 2023-02-11 12:58:49 |

前端js學習中,讓大家最難受的就是異步的問題,解決異步、回調(diào)地獄等問題時你必須得學會promise,對于多數(shù)前端程序員來說promise簡直就是噩夢,本篇文章就是從通俗易懂的角度做為切入點,幫助大家輕松掌握promise

異步編程

想要學習promise,你必須要懂得什么是異步編程!眾所周知,js語言是單線程機制。所謂單線程就是按次序執(zhí)行,執(zhí)行完一個任務再執(zhí)行下一個。但是不影響存在同步異步的兩種操作,這兩種操作做事情其實都是在一條流水線上(單線程),只是這兩種操作在單線程上的執(zhí)行順序不一樣罷了!當js觸發(fā)到異步任務時,會將異步任務交給瀏覽器處理,當執(zhí)行有結果時,會把異步任務的回調(diào)函數(shù)插入待處理隊列的隊尾!

我們通俗的去解釋一下我們的異步:異步就是從主線程發(fā)射一個子線程來完成任務,每一個任務有一個或多個回調(diào)函數(shù)(callback),前一個任務結束后,不是執(zhí)行后一個任務,而是執(zhí)行回調(diào)函數(shù),后一個任務則是不等前一個任務結束就執(zhí)行,所以程序的執(zhí)行順序與任務的排列順序是不一致的、異步的.


(資料圖片)

回調(diào)函數(shù)

回調(diào)函數(shù)的定義非常簡單:一個函數(shù)被當做一個實參傳入到另一個函數(shù)(外部函數(shù)),并且這個函數(shù)在外部函數(shù)內(nèi)被調(diào)用,用來完成某些任務的函數(shù)。就稱為回調(diào)函數(shù)

回調(diào)函數(shù)的兩種寫法(實現(xiàn)效果相同):

const text = () => {   document.write("hello james")}setTimeout(text,1000)
setTimeout(()=>{   document.write("hello james")},1000)

這段代碼中的 setTimeout就是一個消耗時間較長的過程,它的第一個參數(shù)是個回調(diào)函數(shù),第二個參數(shù)是毫秒數(shù),這個函數(shù)執(zhí)行之后會產(chǎn)生一個子線程,子線程會等待 1 秒,然后執(zhí)行回調(diào)函數(shù) "text",在文本中輸出hello james

setTimeout會在子線程中等待1秒,但是主線程的運行不會受到影響!例如以下代碼:

setTimeout(()=>{    document.write("hello davis")},1000)console.log("123456");

在這里會先打印出來123456(主線程),然后一秒后在文本中輸出hello davis(子線程)

回調(diào)地獄

回調(diào)地獄這個詞聽起來就非常的高大上,想要接觸Promise之前,必須要懂得什么是回調(diào)地獄,以及為什么會產(chǎn)生回調(diào)地獄? 先來看看概念:當一個回調(diào)函數(shù)嵌套一個回調(diào)函數(shù)的時候就會出現(xiàn)一個嵌套結構當嵌套的多了就會出現(xiàn)回調(diào)地獄的情況。舉個例子: 比如我們發(fā)送三個 ajax 請求:

第一個正常發(fā)送第二個請求需要第一個請求的結果中的某一個值作為參數(shù)第三個請求需要第二個請求的結果中的某一個值作為參數(shù)

你會看到以下代碼

$.ajax({  url: "我是第一個請求",  type: "get",  success (res) {    // 現(xiàn)在發(fā)送第二個請求    $.ajax({      url: "我是第二個請求",      type:"post",      data: { a: res.a, b: res.b },      success (res1) {        // 進行第三個請求        $.ajax({          url: "我是第三個請求",          type:"post",          data: { a: res1.a, b: res1.b },                  success (res2) {             console.log(res2)           }        })      }    })  }})

這種代碼看起來屬實是折磨人??!當我們把代碼寫成這樣的時候,就陷入了可維護性差的狀態(tài)了,代碼體驗非常的不良好,看一會就給看懵了,為了解決這個問題,于是,就引入了我們的Promise,用Promise去解決回調(diào)地獄問題!

Promise

Promise異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強大,它是一個 ECMAScript 6 提供的類,目的是更加優(yōu)雅地書寫復雜的異步任務。

Promise對象有以下兩個特點:

對象的狀態(tài)不受外界影響。Promise對象代表一個異步操作,有三種狀態(tài):pending(進行中)、fulfilled(已成功)和rejected(已失?。?code>只有異步操作的結果,可以決定當前是哪一種狀態(tài),任何其他操作都無法改變這個狀態(tài)。這也是Promise這個名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變。

一旦狀態(tài)改變,就不會再變,任何時候都可以得到這個結果。Promise對象的狀態(tài)改變,只有兩種可能:從pending變?yōu)閒ulfilled和從pending變?yōu)閞ejected。只要這兩種情況發(fā)生,狀態(tài)就凝固了,不會再變了,會一直保持這個結果,這時就稱為 resolved(已定型)。如果改變已經(jīng)發(fā)生了,你再對Promise對象添加回調(diào)函數(shù),也會立即得到這個結果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監(jiān)聽,是得不到結果的。

兩個特點摘自于??阮一峰ES6文章

Promise語法格式

new Promise(function (resolve, reject) {  // resolve 表示成功的回調(diào)  // reject 表示失敗的回調(diào)}).then(function (res) {  // 成功的函數(shù)}).catch(function (err) {  // 失敗的函數(shù)})

出現(xiàn)了new關鍵字,就明白了Promise對象其實就是一個構造函數(shù),是用來生成Promise實例的。能看出來構造函數(shù)接收了一個函數(shù)作為參數(shù),該函數(shù)就是Promise構造函數(shù)的回調(diào)函數(shù),該函數(shù)中有兩個參數(shù)resolvereject,這兩個參數(shù)也分別是兩個函數(shù)!

簡單的去理解的話resolve函數(shù)的目的是將Promise對象狀態(tài)變成成功狀態(tài),在異步操作成功時調(diào)用,將異步操作的結果,作為參數(shù)傳遞出去。reject函數(shù)的目的是將Promise對象的狀態(tài)變成失敗狀態(tài),在異步操作失敗時調(diào)用,并將異步操作報出的錯誤,作為參數(shù)傳遞出去。

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

代碼示例:

const promise = new Promise((resolve,reject)=>{            //異步代碼            setTimeout(()=>{                // resolve(["111","222","333"])                reject("error")            },2000)        })        promise.then((res)=>{            //兌現(xiàn)承諾,這個函數(shù)被執(zhí)行            console.log("success",res);        }).catch((err)=>{            //拒絕承諾,這個函數(shù)就會被執(zhí)行            console.log("fail",err);        })

代碼分析:

上邊說到Promise是一個構造函數(shù),new之后等于說調(diào)用了構造函數(shù),構造函數(shù)中傳的參數(shù)是一個函數(shù),這個函數(shù)內(nèi)的兩個參數(shù)分別又是兩個函數(shù)(reslovereject),雖然感覺很繞,但是理清思路會很清晰的!

我們得到對象promise,promise對象中自帶有兩個方法thencatch,這兩個方法中會分別再傳入一個回調(diào)函數(shù),這個回調(diào)函數(shù)的目的在于返回你所需要成功或失敗的信息!那么怎么去調(diào)用這兩個回調(diào)函數(shù)呢? 看下方圖可以快速理解:

這兩個函數(shù)分別做為參數(shù)(reslovereject)傳到上方的函數(shù)中去了.隨后在構造函數(shù)的回調(diào)函數(shù)中寫入異步代碼(例如:ajax定時器),這里使用了定時器作為例子,如果你想表達的是成功回調(diào),你可以在內(nèi)部調(diào)用函數(shù)reslove("一般情況下是后端返回的成功數(shù)據(jù))。如果你想表達的是失敗回調(diào),你可以調(diào)用reject("一般情況下是后端返回的失敗信息").

這些就是Promise執(zhí)行的過程!雖然理解著很繞,但是多讀幾遍絕對有不一樣的收獲!

Promise鏈式

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

實際案例:我想要實現(xiàn)在一個數(shù)組中查看一個帖子,但是我最終的目的是得到這個帖子下面的所有評論,這該怎么實現(xiàn)呢?

實現(xiàn)思路先從一個接口中獲取這個帖子的信息,然后通過該帖子的帖子id從而獲取到該帖子下的所有評論

代碼如下:

pajax({    url:"http://localhost:3000/news",    data : {        author : "james"    }}).then(res=>{    return pajax({        url : "http://localhost:3000/comments",        data : {            newsId : res[0].id        }    })}).then(res=>{    console.log(res);}).catch(err=>{    console.log(err);})

代碼分析:

這里使用了一個Promise已經(jīng)封裝過的ajax,我們從第一個接口中得到了帖子id,然后在then中的函數(shù)發(fā)送第二個請求(攜帶了第一個請求返回過來的參數(shù)),我們最后想要拿到第二個接口的結果,于是又有了一個then方法,但是在第一個then方法中要把一個新的Promise實例return出去,這樣的話,第二個then才起作用!(這是因為then方法是Promise 實例所具有的方法,也就是說,then方法是定義在原型對象Promise.prototype上的)====>我們可以打印一下:console.log(Promise.prototype)

可以看的出來原型對象Promise.prototype中是有then方法的!

Promise.all()

Promise.all()方法用于將多個 Promise 實例,包裝成一個新的 Promise 實例。

語法格式:

const p = Promise.all([p1, p2, p3]);

Promise.all()方法接受一個數(shù)組作為參數(shù),p1、p2、p3都是 Promise 實例,如果不是,就會調(diào)用Promise.reslove() [該方法可自行了解]自動將參數(shù)轉(zhuǎn)為 Promise 實例,再進一步處理。

說那么多白話沒用,我們可以根據(jù)一個案例,就可以明白Promise.all()的用途了。

實際案例:如果你想實現(xiàn)一個效果:在一個頁面中,等到頁面中所有的請求返回數(shù)據(jù)后,再渲染頁面,該怎么實現(xiàn)呢?(在實際開發(fā)中我們會看到loading加載頁面,等數(shù)據(jù)返回完后,loading加載頁面會消失,整個頁面就展現(xiàn)出來了,增強用戶的體驗。)

實現(xiàn)思路:通過Promise.all()方法,等多個接口全部接收到數(shù)據(jù)后,再統(tǒng)一進行處理,然后渲染頁面

代碼如下:

console.log("顯示加載中")const q1 = pajax({    url:"http://localhost:3000/looplist"})const q2 = pajax({    url:"http://localhost:3000/datalist"})Promise.all([q1,q2]).then(res=>{    console.log(res)    console.log("隱藏加載中...")}).catch(err=>{    console.log(err)})

代碼分析:

在上方代碼中,全局打印顯示加載中是代替loading的頁面,表示該頁面現(xiàn)在正是loading頁面中,等到q1q2所請求接口都得到返回的信息后,在then方法中接收收據(jù),并且可以進行渲染頁面,同時隱藏了loading加載頁面!

小結

不論是在前端的項目開發(fā)中還是在前端的面試過程中,Promise的地位就是舉足輕重的,雖然解決異步編程的終極解決方案是async和await,但是它們也是基于Promise封裝而來的,在以往文章中,我就說過,學習編程重要的是搞懂某個技術是怎么實現(xiàn)的,而不是做一個cv俠,多去思考,才能進步。繼續(xù)加油吧,少年!

以上就是一文帶你輕松掌握Promise的詳細內(nèi)容,更多請關注php中文網(wǎng)其它相關文章!

關鍵詞: javascript promise