日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務,提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

本篇文章給大家?guī)砹岁P(guān)于javascript的相關(guān)知識,其中主要整理了Promise的基本概念及使用方法的相關(guān)問題,包括了Promise基本概念、使用Promise解決回調(diào)地獄等等內(nèi)容,下面一起來看一下,希望對大家有幫助。


詳細介紹JavaScript中Promise的基本概念及使用方法


一、前言

異步是為了提高CPU的占用率,讓其始終處于忙碌狀態(tài)。

有些操作(最典型的就是I/O)本身不需要CPU參與,而且非常耗時,如果不使用異步就會形成阻塞狀態(tài),CPU空轉(zhuǎn),頁面卡死。

在異步環(huán)境下發(fā)生I/O操作,CPU就把I/O工作扔一邊(此時I/O由其他控制器接手,仍然在數(shù)據(jù)傳輸),然后處理下一個任務,等I/O操作完成后通知CPU(回調(diào)就是一種通知方式)回來干活。

JavaScript異步與回調(diào)》想要表達的核心內(nèi)容是,異步工作的具體結(jié)束時間是不確定的,為了準確的在異步工作完成后進行后繼的處理,就需要向異步函數(shù)中傳入一個回調(diào),從而在完成工作后繼續(xù)下面的任務。

雖然回調(diào)可以非常簡單的實現(xiàn)異步,但是卻會由于多重嵌套形成回調(diào)地獄。避免回調(diào)地獄就需要解嵌套,將嵌套編程改為線性編程。

PromiseJavaScript中處理回調(diào)地獄最優(yōu)解法。

二、Promise基本概念

Promise可以翻譯為“承諾”,我們可以通過把異步工作封裝稱一個Promise,也就是做出一個承諾,承諾在異步工作結(jié)束后給出明確的信號!

Promise語法:

let promise = new Promise(function(resolve,reject){
    // 異步工作})

通過以上語法,我們就可以把異步工作封裝成一個Promise。在創(chuàng)建Promise時傳入的函數(shù)就是處理異步工作的方法,又被稱為executor(執(zhí)行者)。

resolvereject是由JavaScript自身提供的回調(diào)函數(shù),當executor執(zhí)行完了任務就可以調(diào)用:

resolve(result)——如果成功完成,并返回結(jié)果result

reject(error)——如果執(zhí)行是失敗并產(chǎn)生error

executor會在Promise創(chuàng)建完成后立即自動執(zhí)行,其執(zhí)行狀態(tài)會改變Promise內(nèi)部屬性的狀態(tài):

state——最初是pending,然后在resolve被調(diào)用后轉(zhuǎn)為fulfilled,或者在reject被調(diào)用時變?yōu)?code>rejected;

result——最初時undefined,然后在resolve(value)被調(diào)用后變?yōu)?code>value,或者在reject被調(diào)用后變?yōu)?code>error;

2.1 異步工作的封裝

文件模塊的fs.readFile就是一個異步函數(shù),我們可以通過在executor中執(zhí)行文件讀取操作,從而實現(xiàn)對異步工作的封裝。

以下代碼封裝了fs.readFile函數(shù),并使用resolve(data)處理成功結(jié)果,使用reject(err)處理失敗的結(jié)果。

代碼如下:

let promise = new Promise((resolve, reject) => {
    fs.readFile('1.txt', (err, data) => {
        console.log('讀取1.txt')
        if (err) reject(err)
        resolve(data)
    })
})

如果我們執(zhí)行這段代碼,就會輸出“讀取1.txt”字樣,證明在創(chuàng)建Promise后立刻就執(zhí)行了文件讀取操作。

Promise內(nèi)部封裝的通常都是異步代碼,但是并不是只能封裝異步代碼。

2.2 Promise執(zhí)行結(jié)果獲取

以上Promise案例封裝了讀取文件操作,當完成創(chuàng)建后就會立即讀取文件。如果想要獲取Promise執(zhí)行的結(jié)果,就需要使用thencatchfinally三個方法。

then

Promisethen方法可以用來處理Promise執(zhí)行完成后的工作,它接收兩個回調(diào)參數(shù),語法如下:

promise.then(function(result),function(error))

第一個回調(diào)函數(shù)用于處理成功執(zhí)行后的結(jié)果,參數(shù)result就是resolve接收的值;

第二個回調(diào)函數(shù)用于處理失敗執(zhí)行后的結(jié)果,參數(shù)error就是reject接收的參數(shù);

舉例:

let promise = new Promise((resolve, reject) => {
    fs.readFile('1.txt', (err, data) => {
        console.log('讀取1.txt')
        if (err) reject(err)
        resolve(data)
    })
})
promise.then(
    (data) => {
        console.log('成功執(zhí)行,結(jié)果是' + data.toString())
    },
    (err) => {
        console.log('執(zhí)行失敗,錯誤是' + err.message)
    })

如果文件讀取成功執(zhí)行,會調(diào)用第一個函數(shù):

PS E:\Code\Node\demos\03-callback> node .\index.js

讀取1.txt

成功執(zhí)行,結(jié)果是1

刪掉1.txt,執(zhí)行失敗,就會調(diào)用第二個函數(shù):

PS E:\Code\Node\demos\03-callback> node .\index.js

讀取1.txt

執(zhí)行失敗,錯誤是ENOENT: no such file or directory, open 'E:\Code\Node\demos\03-callback\1.txt'

如果我們只關(guān)注成功執(zhí)行的結(jié)果,可以只傳入一個回調(diào)函數(shù):

promise.then((data)=>{
    console.log('成功執(zhí)行,結(jié)果是' + data.toString())
})

到這里我們就是實現(xiàn)了一次文件的異步讀取操作。

catch

如果我們只關(guān)注失敗的結(jié)果,可以把第一個then的回調(diào)傳nullpromise.then(null,(err)=>{...})

亦或者采用更優(yōu)雅的方式:promise.catch((err)=>{...})

let promise = new Promise((resolve, reject) => {
    fs.readFile('1.txt', (err, data) => {
        console.log('讀取1.txt')
        if (err) reject(err)
        resolve(data)
    })})promise.catch((err)=>{
    console.log(err.message)
})

.catch((err)=>{...})then(null,(err)=>{...})作用完全相同。

finally

.finallypromise不論結(jié)果如何都會執(zhí)行的函數(shù),和try...catch...語法中的finally用途一樣,都可以處理和結(jié)果無關(guān)的操作。

例如:

new Promise((resolve,reject)=>{
    //something...
}).finally(()=>{console.log('不論結(jié)果都要執(zhí)行')}).then(result=>{...}, err=>{...})

finally回調(diào)沒有參數(shù),不論成功與否都會執(zhí)行

finally會傳遞promise的結(jié)果,所以在finally后仍然可以.then

三、使用Promise解決回調(diào)地獄

3.1 回調(diào)地獄出現(xiàn)的場景

現(xiàn)在,我們有一個需求:使用fs.readFile()方法順序讀取10個文件,并把十個文件的內(nèi)容順序輸出。

由于fs.readFile()本身是異步的,我們必須使用回調(diào)嵌套的方式,代碼如下:

fs.readFile('1.txt', (err, data) => {
    console.log(data.toString()) //1
    fs.readFile('2.txt', (err, data) => {
        console.log(data.toString())
        fs.readFile('3.txt', (err, data) => {
            console.log(data.toString())
            fs.readFile('4.txt', (err, data) => {
                console.log(data.toString())
                fs.readFile('5.txt', (err, data) => {
                    console.log(data.toString())
                    fs.readFile('6.txt', (err, data) => {
                        console.log(data.toString())
                        fs.readFile('7.txt', (err, data) => {
                            console.log(data.toString())
                            fs.readFile('8.txt', (err, data) => {
                                console.log(data.toString())
                                fs.readFile('9.txt', (err, data) => {
                                    console.log(data.toString())
                                    fs.readFile('10.txt', (err, data) => {
                                        console.log(data.toString())
                                        // ==> 地獄之門
                                    })
                                })
                            })
                        })
                    })
                })
            })
        })
    })
})

雖然以上代碼能夠完成任務,但是隨著調(diào)用嵌套的增加,代碼層次變得更深,維護難度也隨之增加,尤其是我們使用的是可能包含了很多循環(huán)和條件語句的真實代碼,而不是例子中簡單的 console.log(...)

3.2 不使用回調(diào)產(chǎn)生的后果

如果我們不使用回調(diào),直接把fs.readFile()順序的按照如下代碼調(diào)用一遍,會發(fā)生什么呢?

//注意:這是錯誤的寫法
fs.readFile('1.txt', (err, data) => {
    console.log(data.toString())
})
fs.readFile('2.txt', (err, data) => {
    console.log(data.toString())
})
fs.readFile('3.txt', (err, data) => {
    console.log(data.toString())
})
fs.readFile('4.txt', (err, data) => {
    console.log(data.toString())
})
fs.readFile('5.txt', (err, data) => {
    console.log(data.toString())
})
fs.readFile('6.txt', (err, data) => {
    console.log(data.toString())
})
fs.readFile('7.txt', (err, data) => {
    console.log(data.toString())
})
fs.readFile('8.txt', (err, data) => {
    console.log(data.toString())
})
fs.readFile('9.txt', (err, data) => {
    console.log(data.toString())
})
fs.readFile('10.txt', (err, data) => {
    console.log(data.toString())
})

以下是我測試的結(jié)果(每次執(zhí)行的結(jié)果都是不一樣的):

PS E:\Code\Node\demos\03-callback> node .\index.js12346957108

產(chǎn)生這種非順序結(jié)果的原因是異步,并非多線程并行,異步在單線程里就可以實現(xiàn)。

之所以在這里使用這個錯誤的案例,是為了強調(diào)異步的概念,如果不理解為什么會產(chǎn)生這種結(jié)果,一定要回頭補課了!

3.3 Promise解決方案

使用Promise解決異步順序文件讀取的思路:

封裝一個文件讀取promise1,并使用resolve返回結(jié)果

使用promise1.then接收并輸出文件讀取結(jié)果

promise1.then中創(chuàng)建一個新的promise2對象,并返回

調(diào)用新的promise2.then接收并輸出讀取結(jié)果

promise2.then中創(chuàng)建一個新的promise3對象,并返回

調(diào)用新的promise3.then接收并輸出讀取結(jié)果

代碼如下:

let promise1 = new Promise((resolve, reject) => {
    fs.readFile('1.txt', (err, data) => {
        if (err) reject(err)
        resolve(data)
    })
})
let promise2 = promise1.then(
    data => {
        console.log(data.toString())
        return new Promise((resolve, reject) => {
            fs.readFile('2.txt', (err, data) => {
                if (err) reject(err)
                resolve(data)
            })
        })
    }
)
let promise3 = promise2.then(
    data => {
        console.log(data.toString())
        return new Promise((resolve, reject) => {
            fs.readFile('3.txt', (err, data) => {
                if (err) reject(err)
                resolve(data)
            })
        })
    }
)
let promise4 = promise3.then(
    data => {
        console.log(data.toString())
        //.....
    }
)
... ...

這樣我們就把原本嵌套的回調(diào)地獄寫成了線性模式。

但是代碼還存在一個問題,雖然代碼從管理上變的美麗了,但是大大增加了代碼的長度。

3.4 鏈式編程

以上代碼過于冗長,我們可以通過兩個步驟,降低代碼量:

封裝功能重復的代碼,完成文件讀取和輸出工作

省略中間promise的變量創(chuàng)建,將.then鏈接起來

代碼如下:

function myReadFile(path) {
    return new Promise((resolve, reject) => {
        fs.readFile(path, (err, data) => {
            if (err) reject(err)
            console.log(data.toString())
            resolve()
        })
    })
}
myReadFile('1.txt')
.then(data => { return myReadFile('2.txt') })
.then(data => { return myReadFile('3.txt') })
.then(data => { return myReadFile('4.txt') })
.then(data => { return myReadFile('5.txt') })
.then(data => { return myReadFile('6.txt') })
.then(data => { return myReadFile('7.txt') })
.then(data => { return myReadFile('8.txt') })
.then(data => { return myReadFile('9.txt') })
.then(data => { return myReadFile('10.txt') })

由于myReadFile方法會返回一個新的Promise,我們可以直接執(zhí)行.then方法,這種編程方式被稱為鏈式編程

代碼執(zhí)行結(jié)果如下:

PS E:\Code\Node\demos\03-callback> node .\index.js12345678910

這樣就完成了異步且順序的文件讀取操作。

注意:在每一步的.then方法中都必須返回一個新的Promise對象,否則接收到的將是上一個舊的Promise

這是因為每個then方法都會把它的Promise繼續(xù)向下傳遞。


分享到:
標簽:JavaScript Promise基本概念 Promise的使用方法
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定