成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

漫談promise使用場(chǎng)景

劉德剛 / 1501人閱讀

摘要:能幫我們解決什么痛點(diǎn)實(shí)現(xiàn)異步執(zhí)行,在未出現(xiàn)前,我們通常是使用嵌套的回調(diào)函數(shù)來(lái)解決的。那么,接下來(lái)我們看一下使用的實(shí)例可以傳入兩個(gè)參數(shù)表示兩個(gè)狀態(tài)的回調(diào)函數(shù),第一個(gè)是,必選參數(shù)第二個(gè)是,可選參數(shù)的方便之處。

深入理解promise

對(duì)于現(xiàn)在的前端同學(xué)來(lái)說(shuō)你不同promise你都不好意思出門了。對(duì)于前端同學(xué)來(lái)說(shuō)promise已經(jīng)成為了我們的必備技能。

那么,下面我們就來(lái)說(shuō)一說(shuō)promise是什么,它能幫助我們解決什么問題,我們應(yīng)該如何使用它?

這是我個(gè)人對(duì)promise的理解。歡迎吐槽 :)

Promise是什么

promise的意思是承諾,有的人翻譯為許愿,但它們代表的都是未實(shí)現(xiàn)的東西,等待我們接下來(lái)去實(shí)現(xiàn)。

Promise最早出現(xiàn)在commnjs,隨后形成了Promise/A規(guī)范。在Promise這個(gè)技術(shù)中它本身代表以目前還不能使用的對(duì)象,但可以在將來(lái)的某個(gè)時(shí)間點(diǎn)被調(diào)用。使用Promise我們可以用同步的方式寫異步代碼。其實(shí)Promise在實(shí)際的應(yīng)用中往往起到代理的作用。例如,我們像我們發(fā)出請(qǐng)求調(diào)用服務(wù)器數(shù)據(jù),由于網(wǎng)絡(luò)延時(shí)原因,我們此時(shí)無(wú)法調(diào)用到數(shù)據(jù),我們可以接著執(zhí)行其它任務(wù),等到將來(lái)某個(gè)時(shí)間節(jié)點(diǎn)服務(wù)器響應(yīng)數(shù)據(jù)到達(dá)客戶端,我們即可使用promise自帶的一個(gè)回調(diào)函數(shù)來(lái)處理數(shù)據(jù)。

Promise能幫我們解決什么痛點(diǎn)

JavaScript實(shí)現(xiàn)異步執(zhí)行,在Promise未出現(xiàn)前,我們通常是使用嵌套的回調(diào)函數(shù)來(lái)解決的。但是使用回調(diào)函數(shù)來(lái)解決異步問題,簡(jiǎn)單還好說(shuō),但是如果問題比較復(fù)雜,我們將會(huì)面臨回調(diào)金字塔的問題(pyramid of Doom)。

var a = function() {
    console.log("a");
};

var b = function() {
    console.log("b");
};

var c = function() {
    for(var i=0;i<100;i++){
        console.log("c")
    }  
};

a(b(c)); // 100個(gè)c -> b -> a

我們要桉順序的執(zhí)行a,b,c三個(gè)函數(shù),我們發(fā)現(xiàn)嵌套回調(diào)函數(shù)確實(shí)可以實(shí)現(xiàn)異步操作(在c函數(shù)中循環(huán)100次,發(fā)現(xiàn)確實(shí)是先輸出100個(gè)c,然后在輸出b,最后是a)。但是你發(fā)現(xiàn)沒這種實(shí)現(xiàn)可讀性極差,如果是幾十上百且回調(diào)函數(shù)異常復(fù)雜,那么代碼維護(hù)起來(lái)將更加麻煩。

那么,接下來(lái)我們看一下使用promise(promise的實(shí)例可以傳入兩個(gè)參數(shù)表示兩個(gè)狀態(tài)的回調(diào)函數(shù),第一個(gè)是resolve,必選參數(shù);第二個(gè)是reject,可選參數(shù))的方便之處。

var promise = new Promise(function(resolve, reject){
    console.log("............");
    resolve(); // 這是promise的一個(gè)機(jī)制,只有promise實(shí)例的狀態(tài)變?yōu)閞esolved,才會(huì)會(huì)觸發(fā)then回調(diào)函數(shù)
});

promise.then(function(){
    for(var i=0;i<100;i++) {
        console.log("c")
    }    
})
.then(function(){
    console.log("b")
})
.then(function(){
    console.log("a")
})

那么,為什么嵌套的回調(diào)函數(shù)這種JavaScript自帶實(shí)現(xiàn)異步機(jī)制不招人喜歡呢,因?yàn)樗目勺x性差,可維護(hù)性差;另一方面就是我們熟悉了jQuery的鏈?zhǔn)秸{(diào)用。所以,相比起來(lái)我們會(huì)更喜歡Promise的風(fēng)格。

promise的3種狀態(tài)

上面提到了promise的 resolved 狀態(tài),那么,我們就來(lái)說(shuō)一下promise的3種狀態(tài),未完成(unfulfilled)、完成(fulfilled)、失?。╢ailed)。

在promise中我們使用resolved代表fulfilled,使用rejected表示fail。

ES6的Promise有哪些特性

promise的狀態(tài)只能從 未完成->完成, 未完成->失敗 且狀態(tài)不可逆轉(zhuǎn)。

promise的異步結(jié)果,只能在完成狀態(tài)時(shí)才能返回,而且我們?cè)陂_發(fā)中是根據(jù)結(jié)果來(lái)選擇來(lái)選擇狀態(tài)的,然后根據(jù)狀態(tài)來(lái)選擇是否執(zhí)行then()。

實(shí)例化的Promise內(nèi)部會(huì)立即執(zhí)行,then方法中的異步回調(diào)函數(shù)會(huì)在腳本中所有同步任務(wù)完成時(shí)才會(huì)執(zhí)行。因此,promise的異步回調(diào)結(jié)果最后輸出。示例代碼如下:

var promise = new Promise(function(resolve, reject) {
  console.log("Promise instance");
  resolve();
});

promise.then(function() {
  console.log("resolved result");
});
for(var i=0;i<100;i++) {
console.log(i);
/*
Promise instance
1
2
3
...
99
100
resolved result
*/

上面的代碼執(zhí)行輸出結(jié)果的先后順序,曾經(jīng)有人拿到這樣一個(gè)面試題問過(guò)我,所以,這個(gè)問題還是要注意的。

resolve中可以接受另一個(gè)promise實(shí)例

resolve中接受另一個(gè)另一個(gè)對(duì)象的實(shí)例后,resolve本實(shí)例的返回狀態(tài)將會(huì)有被傳入的promise的返回狀態(tài)來(lái)取代。

reject狀態(tài)替換實(shí)例,代碼如下:

const p1 = new Promise(function (resolve, reject) {
    cosole.log("2秒之后,調(diào)用返回p1的reject給p2");
    setTimeout(reject, 3000, new Error("fail"))
})

const p2 = new Promise(function (resolve, reject) {
    cosole.log("1秒之后,調(diào)用p1");
    setTimeout(() => resolve(p1), 1000)
})

p2
  .then(result => console.log(result))
  .catch(error => console.log(error))

// fail

resolve狀態(tài)替換實(shí)例,代碼如下:

const p1 = new Promise(function (resolve, reject) {
    cosole.log("2秒之后,調(diào)用返回p1的resolve給p2");
    setTimeout(resolve, 3000, "success")
})

const p2 = new Promise(function (resolve, reject) {
    cosole.log("1秒之后,調(diào)用p1");
    setTimeout(() => resolve(p1), 1000)
})

p2
  .then(result => console.log(result))
  .catch(error => console.log(error))

// success

注意:promise實(shí)例內(nèi)部的resolve也執(zhí)行的是異步回調(diào),所以不管resolve放的位置靠前還是靠后,都要等內(nèi)部的同步函數(shù)執(zhí)行完畢,才會(huì)執(zhí)行resolve異步回調(diào)。

new Promise((resolve, reject) => {
    console.log(1);
    resolve(2);
    console.log(3);
}).then(result => {
    console.log(result);
});
/*
1
3
2
*/

這個(gè)問題也在面試題中出現(xiàn)過(guò),所以,要牢記。

promise和ajax如何結(jié)合使用
function PromiseGet (url) {
    return new Promise( (resolve, reject) => {
        let xhr = new XMLHttpRequest()
        xhr.open("GET", url, true)
        xhr.onreadystatechange = function () {
            if (this.readyState === 4) {
                if (this.status === 200) {
                    resolve(this.responseText, this)
                } else {
                    let resJson = {
                        code: this.status,
                        response: this.response
                    }
                    reject(resJson, this)
                }
            }
        }
        xhr.send()
    })
}

我們發(fā)現(xiàn)用promise技術(shù)結(jié)合ajax,只是在promise實(shí)例中引入ajax,在ajax請(qǐng)求處理的結(jié)果中使用了resolve和reject狀態(tài)。

前面我們說(shuō)了resolve(),返回執(zhí)行then()代表完成,那么,reject()代表失敗,返回執(zhí)行catch(),同時(shí)運(yùn)行中拋出的錯(cuò)誤也會(huì)執(zhí)行catch()

現(xiàn)在有一個(gè)非常好用的promise和Ajax結(jié)合的github項(xiàng)目Axios ,想要深入了解的同學(xué)可以研究下它的源碼。

promise.all()方法可以處理一個(gè)以promise實(shí)例為元素的數(shù)組

let promise = Promise.all([p1, p2, p3])

promise 的狀態(tài)由p1,p2,p3共同決定。當(dāng)它們都為resolve狀態(tài)時(shí),promise狀態(tài)為true,它們的返回值組成一個(gè)數(shù)組,傳遞給promise;它們只要有一個(gè)的狀態(tài)為reject,就將該實(shí)例的返回值傳遞給promise

promise.race()方法也可以處理一個(gè)promise實(shí)例數(shù)組

但它和promise.all()不同,從字面意思上理解就是競(jìng)速,那么理解起來(lái)上就簡(jiǎn)單多了,也就是說(shuō)在數(shù)組中的元素實(shí)例那個(gè)率先改變狀態(tài),就向下傳遞誰(shuí)的狀態(tài)和異步結(jié)果。

將一個(gè)普通對(duì)象轉(zhuǎn)化為Promise對(duì)象

在開發(fā)中我們經(jīng)常會(huì)遇到$.ajax()的使用且會(huì)遇到$.ajax()間的依賴使用,由于兩個(gè)或多個(gè)$.ajax()間是同步的,如果我們并排著寫實(shí)現(xiàn)不了依賴關(guān)系,所以,我們往往使用嵌套,但是對(duì)于ajax這樣復(fù)雜的結(jié)構(gòu),嵌套不是個(gè)好辦法,我們需要先將代碼抽象提取,做一下封裝,代碼如下:

/*
url:地址
data:數(shù)據(jù),在函數(shù)內(nèi)部會(huì)轉(zhuǎn)化成json。如果沒傳,表示用GET方法;如果傳了,表示用POST方法
*/
function ajax(url, data, callback) {
    $.ajax({
      url: url,
      type: data == null ? "GET" : "POST",
      dataType: "json",
      data: data == null ? "" : JSON.stringify(data),
      async: true,
      contentType: "application/json",
      success: function (data) {
          callback(data);
      },
      error: function (XMLHttpRequest, textStatus) {
        if (XMLHttpRequest.status == "401") {
            window.parent.location = "...";
            self.location = "...";
        } else {
            alert(XMLHttpRequest.responseText);
        }
      }
    });
}

那么,我們應(yīng)該如何避免回調(diào)金字塔呢?很顯然,我們可以將它與promise結(jié)合,代碼如下:

function ajax(url, data, callback) =>
    new Promise((resolve, reject) => {
        $.ajax({
            url: url,
            type: data == null ? "GET" : "POST",
            dataType: "json",
            data: data == null ? "" : JSON.stringify(data),
            async: true,
            contentType: "application/json",
            success: function (data) {
                callback(data);
                resolve();
            },
            error: function (XMLHttpRequest, textStatus) {
                if (XMLHttpRequest.status == "401") {
                    window.parent.location = "..."
                    self.location = "..."
                } else {
                    alert(XMLHttpRequest.responseText);
                }
                reject()
            }
        })
    })  
}

當(dāng)然,這是不熟悉jQuery的同學(xué),或者考慮長(zhǎng)線Promise的,但是jQuery也為我們提供了按順序調(diào)用多個(gè)$.ajax()的方案,那就是deferred,它模擬了promise的實(shí)現(xiàn),有興趣的同學(xué)可以查看源碼,看它是如何實(shí)現(xiàn)的。實(shí)例代碼如下:

$.ajax({
    url:"./a"
}).then(function(){
    return $.ajax({ url:"./b" });
}).then(function(){
    return $.ajax({ url:"./c" });
}).then(function(){
    return $.ajax({ url:"./d" });
}).then(function(){
    //TODO here
});
promise存在的問題

promise一旦執(zhí)行,無(wú)法中途取消

promise的錯(cuò)誤無(wú)法在外部被捕捉到,只能在內(nèi)部進(jìn)行預(yù)判處理

promise的內(nèi)如何執(zhí)行,監(jiān)測(cè)起來(lái)很難

正是因?yàn)檫@些原因,ES7引入了更加靈活多變的async,await來(lái)處理異步。

這個(gè)稍后,后續(xù)可能還會(huì)繼續(xù)修改,也歡迎各位批評(píng)指正。有問題或者有其他想法的可以在我的GitHub上pr。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/107183.html

相關(guān)文章

  • [前端漫談_3] 從 filter 聊到 Promise

    摘要:前言在學(xué)習(xí)前端的時(shí)候,我總是能聽到很多高級(jí)詞匯,比如今天會(huì)聊到的函數(shù)式編程高階函數(shù)。接下來(lái)我們看看,高階函數(shù)有可能會(huì)遇到的問題,又如何去解決。 前言 在學(xué)習(xí)前端的時(shí)候,我總是能聽到很多高級(jí)詞匯,比如今天會(huì)聊到的 函數(shù)式編程(Functional Programming) & 高階函數(shù) (Higher-order function) 。但是當(dāng)你真正的理解什么是 函數(shù)式編程 & 高階函數(shù) ...

    crossoverJie 評(píng)論0 收藏0
  • [前端漫談_2] 從 Dva 的 Effect 到 Generator + Promise 實(shí)現(xiàn)異步

    摘要:你能學(xué)到什么如何使用實(shí)現(xiàn)異步編程異步編程的原理解析前言結(jié)合上一篇文章,我們來(lái)聊聊基礎(chǔ)原理說(shuō)到異步編程,你想到的是和,但那也只是的語(yǔ)法糖而已。表示一個(gè)異步操作的最終狀態(tài)完成或失敗,以及其返回的值。至此實(shí)現(xiàn)異步操作的控制。 你能學(xué)到什么 如何使用 Generator + Promise 實(shí)現(xiàn)異步編程 異步編程的原理解析 前言 結(jié)合 上一篇文章 ,我們來(lái)聊聊 Generator 基礎(chǔ)原理...

    pekonchan 評(píng)論0 收藏0
  • 漫談前端性能 突破 React 應(yīng)用瓶頸

    摘要:表示調(diào)用棧在下一將要執(zhí)行的任務(wù)。兩方性能解藥我們一般有兩種方案突破上文提到的瓶頸將耗時(shí)高成本高易阻塞的長(zhǎng)任務(wù)切片,分成子任務(wù),并異步執(zhí)行這樣一來(lái),這些子任務(wù)會(huì)在不同的周期執(zhí)行,進(jìn)而主線程就可以在子任務(wù)間隙當(dāng)中執(zhí)行更新操作。 showImg(https://segmentfault.com/img/remote/1460000016008111); 性能一直以來(lái)是前端開發(fā)中非常重要的話題...

    whlong 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<