亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Promise必知必會(huì)

muzhuyu / 1319人閱讀

摘要:而真正的回調(diào)函數(shù),是在的外面被調(diào)用的,也就是和中調(diào)用方法返回的是一個(gè)新的實(shí)例注意,不是原來那個(gè)實(shí)例。

前端開發(fā)中經(jīng)常會(huì)進(jìn)行一些異步操作,常見的異步有:

網(wǎng)絡(luò)請(qǐng)求:ajax

IO操作: readFile

定時(shí)器:setTimeout

博客地址

回調(diào)

最基礎(chǔ)的異步解決方案莫過于回調(diào)函數(shù)了

前端經(jīng)常會(huì)在成功時(shí)和失敗時(shí)分別注冊(cè)回調(diào)函數(shù)

const req = new XMLHttpRequest();
req.open("GET", URL, true);
req.onload = function () {
    // 成功的回調(diào)
    if (req.status === 200) {
        console.log(req.statusText)
    }
};
req.onerror = function () {
    // 失敗的回調(diào)
    console.log(req.statusText)
};
req.send();

node的異步api,則通常只注冊(cè)一個(gè)回調(diào)函數(shù),通過約定的參數(shù)來判斷到底是成功還是失敗:

const fs = require("fs");
fs.readFile("input.txt", function (err, data) {
    // 回調(diào)函數(shù)
    // 第一個(gè)參數(shù)是err,如果有err,則表示調(diào)用失敗
   if (err) {
       return console.error(err);
   }
   console.log("異步讀取: " + data.toString());
});

回調(diào)的異步解決方案本身也簡(jiǎn)單易懂,但是它有一個(gè)致命的缺點(diǎn):無法優(yōu)雅的控制異步流程

什么意思?

單個(gè)異步當(dāng)然可以很簡(jiǎn)單的使用回調(diào)函數(shù),但是對(duì)于多個(gè)異步操作,就會(huì)陷入回調(diào)地獄中

// 請(qǐng)求data1成功后再請(qǐng)求data2,最后請(qǐng)求data3
const ajax = $.ajax({
    url: "data1.json",
    success: function(data1) {
        console.log(data1);
        $.ajax({
            url: "data2.json",
            success: function(data2) {
                console.log(data2);
                $.ajax({
                    url: "data3.json",
                    success: function(data3) {
                        console.log(data3);

                    }
                })
            }
        })
    }
})

這種要按順序進(jìn)行異步流程控制的場(chǎng)景,回調(diào)函數(shù)就顯得捉襟見肘了。這時(shí),Promise的異步解決方案就被提了出來。

Promise

當(dāng)初在學(xué)Promise時(shí),看得我真是一臉懵逼,完全不明白這貨到底怎么用。其實(shí),Promise的api要分成兩部分來理解:

Promise構(gòu)造函數(shù):resolve reject (改變內(nèi)部狀態(tài))

Promise對(duì)象: then catch (流程控制)

Promise對(duì)象

Promise對(duì)象代表一個(gè)異步操作,有三種狀態(tài):pending(進(jìn)行中)、fulfilled(已成功)和rejected(已失?。?/p>

初始時(shí),該對(duì)象狀態(tài)為pending,之后只能變成fulfilled和rejected其中的一個(gè)

then方法有兩個(gè)參數(shù),分別對(duì)應(yīng)狀態(tài)為fulfilled和rejected時(shí)的回調(diào)函數(shù),其中第二個(gè)參數(shù)可選

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

通常我們會(huì)省略then的第二個(gè)參數(shù),而改用catch來注冊(cè)狀態(tài)變?yōu)閞ejected時(shí)的回調(diào)函數(shù)

promise.then(function(value) {
  // success
}).catch(function(error) {
  // failure
});
Promise構(gòu)造函數(shù)

Promise對(duì)象怎么生成的呢?就是通過構(gòu)造函數(shù)new出來的。

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

Promise構(gòu)造函數(shù)接收一個(gè)函數(shù)作為參數(shù),這個(gè)函數(shù)可以接收兩個(gè)參數(shù):resolve和reject

resolve, reject是兩個(gè)函數(shù),由JavaScript引擎提供,不用自己編寫

前面我們說過,Promise對(duì)象有三種狀態(tài),初始時(shí)為pending,之后可以變成fulfilled或者rejected,那怎么改變狀態(tài)呢?答案就是調(diào)用resolve或者reject

調(diào)用resolve時(shí),狀態(tài)變成fulfilled,表示異步已經(jīng)完成;調(diào)用reject時(shí),狀態(tài)變成rejected,表示異步失敗。

回調(diào)和Promise的對(duì)比

其實(shí)這里就是Promise最難理解的地方了,我們先看下例子:

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

function getURL(URL, success, error) {
    const req = new XMLHttpRequest();
    req.open("GET", URL, true);
    req.onload = function () {
        if (req.status === 200) {
            success(req.responseText);
        } else {
            error(new Error(req.statusText));
        }
    };
    req.onerror = function () {
        error(new Error(req.statusText));
    };
    req.send();
}
const URL = "http://httpbin.org/get";
getURL(URL, function onFulfilled(value) {
    console.log(value);
}, function onRejected(error) {
    console.error(error);
})

Promise封裝

function getURL(URL) {
    return new Promise(function (resolve, reject) {
        const req = new XMLHttpRequest();
        req.open("GET", URL, true);
        req.onload = function () {
            if (req.status === 200) {
                resolve(req.responseText);
            } else {
                reject(new Error(req.statusText));
            }
        };
        req.onerror = function () {
            reject(new Error(req.statusText));
        };
        req.send();
    });
}

const URL = "http://httpbin.org/get";
getURL(URL).then(function onFulfilled(value){
    console.log(value);
}).catch(function onRejected(error){
    console.error(error);
});

兩段代碼最大的區(qū)別就是:

用回調(diào)函數(shù)封裝的getURL函數(shù),需要明顯的傳給它成功和失敗的回調(diào)函數(shù),success和error的最終調(diào)用是在getURL里被調(diào)用的

用Promise封裝的getURL函數(shù),完全不關(guān)心成功和失敗的回調(diào)函數(shù),它只需要在ajax成功時(shí)調(diào)用resolve(),告訴promise對(duì)象,你現(xiàn)在的狀態(tài)變成了fulfilled,在ajax失敗時(shí),調(diào)用reject()。而真正的回調(diào)函數(shù),是在getURL的外面被調(diào)用的,也就是then和catch中調(diào)用

then方法返回的是一個(gè)新的Promise實(shí)例(注意,不是原來那個(gè)Promise實(shí)例)。因此可以采用鏈?zhǔn)綄懛?,即then方法后面再調(diào)用另一個(gè)then方法。

function getURL(URL) {
    return new Promise(function (resolve, reject) {
        const req = new XMLHttpRequest();
        req.open("GET", URL, true);
        req.onload = function () {
            if (req.status === 200) {
                resolve(req.responseText);
            } else {
                reject(new Error(req.statusText));
            }
        };
        req.onerror = function () {
            reject(new Error(req.statusText));
        };
        req.send();
    });
}

const URL = "http://httpbin.org/get";
const URL2 = "http://deepred5.com/cors.php?search=ntr";
getURL(URL).then(function onFulfilled(value){
    console.log(value);
    // 返回了一個(gè)新的Promise對(duì)象
    return getURL(URL2)
}).then(function onFulfilled(value){
    console.log(value);
}).catch(function onRejected(error){
    console.error(error);
});

這段代碼就充分說明了Promise對(duì)于流程控制的優(yōu)勢(shì):讀取URL的數(shù)據(jù)后再讀取URL2,沒有了之前的回調(diào)地獄問題。

Promise應(yīng)用

Promise經(jīng)常用于對(duì)函數(shù)的異步流程封裝

function getURL(URL) {
    return new Promise(function (resolve, reject) {
        const req = new XMLHttpRequest();
        req.open("GET", URL, true);
        req.onload = function () {
            if (req.status === 200) {
                resolve(req.responseText);
            } else {
                reject(new Error(req.statusText));
            }
        };
        req.onerror = function () {
            reject(new Error(req.statusText));
        };
        req.send();
    });
}
const preloadImage = function (path) {
  return new Promise(function (resolve, reject) {
    const image = new Image();
    image.onload  = resolve;
    image.onerror = reject;
    image.src = path;
  });
};
const fs = require("fs")
const path = require("path") 
const readFilePromise = function (fileName) {
    return new Promise((resolve, reject) => {
        fs.readFile(fileName, (err, data) => {
            if (err) {
                reject(err)
            } else {
                resolve(data.toString())
            }
        })
    })
}

結(jié)合上面幾個(gè)例子,我們可以看出Promise封裝代碼的基本套路:

const methodPromise = function() {
    return new Promise((resolve, reject) => {
        // 異步流程
        if (/* 異步操作成功 */){
            resolve(value);
        } else {
            reject(error);
        }
    })
}
Promise.race Promise.all

Promise.all 接收一個(gè)promise對(duì)象的數(shù)組作為參數(shù),當(dāng)這個(gè)數(shù)組里的所有promise對(duì)象全部變?yōu)閞esolve的時(shí)候,它才會(huì)去調(diào)用then方法,如果其中有一個(gè)變?yōu)閞ejected,就直接調(diào)用catch方法

傳給then方法的是一個(gè)數(shù)組,里面分別對(duì)應(yīng)promise返回的結(jié)果

function getURL(URL) {
    return new Promise(function (resolve, reject) {
        const req = new XMLHttpRequest();
        req.open("GET", URL, true);
        req.onload = function () {
            if (req.status === 200) {
                resolve(req.responseText);
            } else {
                reject(new Error(req.statusText));
            }
        };
        req.onerror = function () {
            reject(new Error(req.statusText));
        };
        req.send();
    });
}

Promise.all([getURL("http://deepred5.com/cors.php?search=ntr"), getURL("http://deepred5.com/cors.php?search=rbq")])
.then((dataArr) => {
    const [data1, data2] = dataArr;
}).catch((err) => {
    console.log(err)
})

Promise.race類似,只不過只要有一個(gè)Promise變成resolve就調(diào)用then方法

Promise.resolve Promise.reject
Promise.resolve(42); 
// 等價(jià)于
new Promise(function(resolve){
    resolve(42);
});

Promise.reject(new Error("出錯(cuò)了"))
// 等價(jià)于
new Promise(function(resolve,reject){
    reject(new Error("出錯(cuò)了"));
});
Promise.resolve(42).then(function(value){
    console.log(value);
});

Promise.reject(new Error("出錯(cuò)了")).catch(function(error){
    console.error(error);
});

Promise.resolve方法另一個(gè)作用就是將thenable對(duì)象轉(zhuǎn)換為promise對(duì)象

const promise = Promise.resolve($.ajax("/json/comment.json"));// => promise對(duì)象
promise.then(function(value){
   console.log(value);
});

thenable對(duì)象指的是具有then方法的對(duì)象:

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};
let p1 = Promise.resolve(thenable);
p1.then(function(value) {
  console.log(value);  // 42
});
異常捕獲

理想狀態(tài)下,Promise可以通過catch捕獲到異常,但是如果我們沒有使用catch,那么雖然控制臺(tái)會(huì)打印錯(cuò)誤,但是這次錯(cuò)誤并不會(huì)終止腳本執(zhí)行


上述代碼只會(huì)打印2


打印1和2

解決方法:
window有一個(gè)unhandledRejection事件,專門監(jiān)聽未捕獲的reject錯(cuò)誤

window.onunhandledrejection = function(e) {
    console.log(e.reason);
}
const promise = new Promise((resolve, reject) => {
    const a = b.c.d;
    resolve("ok");
})
promise.then(data => {
    console.log(data)
})
參考

ECMAScript 6 入門

JavaScript Promise迷你書

深入理解 JavaScript 異步

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

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

相關(guān)文章

  • 前端必知必會(huì)HTTP請(qǐng)求系列(二)簡(jiǎn)單一點(diǎn)的HTTP協(xié)議

    摘要:通過請(qǐng)求和響應(yīng)的交換達(dá)成通信協(xié)議中已經(jīng)規(guī)定了請(qǐng)求是從客戶端發(fā)出,最后由服務(wù)端響應(yīng)這個(gè)請(qǐng)求并返回。隨后的字符串指明了請(qǐng)求訪問的資源對(duì)象。協(xié)議自身不對(duì)請(qǐng)求和響應(yīng)之間的通信狀態(tài)進(jìn)行保存,也就是說這個(gè)級(jí)別。從前發(fā)送請(qǐng)求后需等待并受到響應(yīng)。 showImg(https://segmentfault.com/img/bVbmDsG?w=1024&h=538); http協(xié)議用戶客戶端和服務(wù)器之間的...

    xbynet 評(píng)論0 收藏0
  • 前端必知必會(huì)HTTP請(qǐng)求系列(三)HTTP報(bào)文內(nèi)的http信息

    摘要:報(bào)文用于協(xié)議交互的信息被稱為報(bào)文?,F(xiàn)在出現(xiàn)的各種首部字段及狀態(tài)碼稍后會(huì)闡述。狀態(tài)碼響應(yīng)報(bào)文包含了多個(gè)范圍的內(nèi)容使用。如果服務(wù)器無法響應(yīng)范圍請(qǐng)求,則會(huì)返回狀態(tài)碼和完整的實(shí)體內(nèi)容。 showImg(https://segmentfault.com/img/bVbthNL?w=900&h=500); http報(bào)文 用于HTTP協(xié)議交互的信息被稱為HTTP報(bào)文。請(qǐng)求端的http報(bào)文叫做請(qǐng)求報(bào)文...

    Invoker 評(píng)論0 收藏0
  • [ 學(xué)習(xí)路線 ] 2015 前端(JS)工程師必知必會(huì) (2)

    摘要:轉(zhuǎn)自前端外刊評(píng)論非常感謝,翻譯的很好,受益很多,轉(zhuǎn)到此處讓前端小伙伴們也驚呆下上次我寫前端工程師必知必會(huì)已經(jīng)是三年前了,那是我寫過最火的文章了。測(cè)試的第二大障礙是工具。 轉(zhuǎn)自:前端外刊評(píng)論 非常感謝,翻譯的很好,受益很多,轉(zhuǎn)到此處讓前端小伙伴們也驚呆下........ 上次我寫《前端工程師必知必會(huì)》已經(jīng)是三年前了,那是我寫過最火的文章了。三年了,我仍然會(huì)在Twitter上...

    stefan 評(píng)論0 收藏0
  • [ 學(xué)習(xí)路線 ] 2015 前端(JS)工程師必知必會(huì) (2)

    摘要:轉(zhuǎn)自前端外刊評(píng)論非常感謝,翻譯的很好,受益很多,轉(zhuǎn)到此處讓前端小伙伴們也驚呆下上次我寫前端工程師必知必會(huì)已經(jīng)是三年前了,那是我寫過最火的文章了。測(cè)試的第二大障礙是工具。 轉(zhuǎn)自:前端外刊評(píng)論 非常感謝,翻譯的很好,受益很多,轉(zhuǎn)到此處讓前端小伙伴們也驚呆下........ 上次我寫《前端工程師必知必會(huì)》已經(jīng)是三年前了,那是我寫過最火的文章了。三年了,我仍然會(huì)在Twitter上...

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

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

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<