亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript中Promise的基本概念及使用方法是什么

發布時間:2022-07-12 14:04:13 來源:億速云 閱讀:120 作者:iii 欄目:web開發

本篇內容主要講解“JavaScript中Promise的基本概念及使用方法是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“JavaScript中Promise的基本概念及使用方法是什么”吧!

JavaScript中Promise的基本概念及使用方法是什么

一、前言

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

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

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

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

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

PromiseJavaScript中處理回調地獄最優解法。

二、Promise基本概念

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

Promise語法:

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

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

resolvereject是由JavaScript自身提供的回調函數,當executor執行完了任務就可以調用:

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

  • reject(error)——如果執行是失敗并產生error

executor會在Promise創建完成后立即自動執行,其執行狀態會改變Promise內部屬性的狀態:

  • state——最初是pending,然后在resolve被調用后轉為fulfilled,或者在reject被調用時變為rejected

  • result——最初時undefined,然后在resolve(value)被調用后變為value,或者在reject被調用后變為error;

2.1 異步工作的封裝

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

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

代碼如下:

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

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

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

2.2 Promise執行結果獲取

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

then

Promisethen方法可以用來處理Promise執行完成后的工作,它接收兩個回調參數,語法如下:

promise.then(function(result),function(error))
  • 第一個回調函數用于處理成功執行后的結果,參數result就是resolve接收的值;

  • 第二個回調函數用于處理失敗執行后的結果,參數error就是reject接收的參數;

舉例:

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('成功執行,結果是' + data.toString())
    },
    (err) => {
        console.log('執行失敗,錯誤是' + err.message)
    })

如果文件讀取成功執行,會調用第一個函數:

PS E:\Code\Node\demos\03-callback> node .\index.js
讀取1.txt
成功執行,結果是1

刪掉1.txt,執行失敗,就會調用第二個函數:

PS E:\Code\Node\demos\03-callback> node .\index.js
讀取1.txt
執行失敗,錯誤是ENOENT: no such file or directory, open 'E:\Code\Node\demos\03-callback\1.txt'

如果我們只關注成功執行的結果,可以只傳入一個回調函數:

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

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

catch

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

亦或者采用更優雅的方式: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不論結果如何都會執行的函數,和try...catch...語法中的finally用途一樣,都可以處理和結果無關的操作。

例如:

new Promise((resolve,reject)=>{
    //something...}).finally(()=>{console.log('不論結果都要執行')}).then(result=>{...}, err=>{...})
  • finally回調沒有參數,不論成功與否都會執行

  • finally會傳遞promise的結果,所以在finally后仍然可以.then

三、使用Promise解決回調地獄

3.1 回調地獄出現的場景

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

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

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())
                                        // ==> 地獄之門
                                    })
                                })
                            })
                        })
                    })
                })
            })
        })
    })})

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

3.2 不使用回調產生的后果

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

//注意:這是錯誤的寫法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())})

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

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

產生這種非順序結果的原因是異步,并非多線程并行,異步在單線程里就可以實現。

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

3.3 Promise解決方案

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

  1. 封裝一個文件讀取promise1,并使用resolve返回結果

  2. 使用promise1.then接收并輸出文件讀取結果

  3. promise1.then中創建一個新的promise2對象,并返回

  4. 調用新的promise2.then接收并輸出讀取結果

  5. promise2.then中創建一個新的promise3對象,并返回

  6. 調用新的promise3.then接收并輸出讀取結果

代碼如下:

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())
        //.....
    })... ...

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

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

3.4 鏈式編程

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

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

  • 省略中間promise的變量創建,將.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,我們可以直接執行.then方法,這種編程方式被稱為鏈式編程

代碼執行結果如下:

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

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

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

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

到此,相信大家對“JavaScript中Promise的基本概念及使用方法是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

突泉县| 高平市| 淳化县| 碌曲县| 伊宁市| 类乌齐县| 大港区| 望谟县| 浦县| 基隆市| 景德镇市| 庆城县| 庄河市| 蒲城县| 邯郸市| 开封市| 周口市| 当雄县| 金塔县| 八宿县| 墨脱县| 民县| 开化县| 资溪县| 莆田市| 通州市| 尼勒克县| 隆德县| 上饶市| 平罗县| 绵竹市| 托克托县| 新和县| 宁阳县| 丹寨县| 盐亭县| 连城县| 九龙县| 怀安县| 肇庆市| 乐昌市|