Vue.js 之 Promise 對象(七)


一、Promise 概念

Promise 是一個構造函數,new Promise() 可以得到一個 Promise 實例對象,它是一個異步操作,可以用來執行一些異步操作(異步操作不能直接 return 接收執行結果,只能通過回調來接收)。

回調函數

  • resolve():成功之后調用的回調函數
  • reject():執行失敗調用的回調函數

實例對象/方法

Prototype 屬性有一個 .then() 方法,它可以預先為 Promise 異步操作指定 成功 resolve() 和失敗 reject() 的回調Promise 實例對象可直接調用 .then() 方法。

注意:可以在瀏覽器調試界面打印輸出 Promise 對象的內置方法,使用方法:console.dir(Promise)

二、形式上的異步操作和具體的異步操作

形式上的異步操作(只是形式上的,並沒有其他任何異步操作):

var promise = new Promise()		

具體的異步操作:

var promise = new Promise(function(){
  // function 內部就是具體的異步操作
})

三、快速上手

創建一個 Promise 對象,用於讀取文件內容,新建 read_file.js

const fs = require('fs')

// new 一個 Promise() 對象,內部異步操作:讀寫文件
var promise = new Promise(function () {
    fs.readFile('./files/1.txt', 'utf-8', (err, resp) => {
        if (err) throw err
        // if (err) throw err      // 若讀寫文件有錯,則 throw 掉,不執行這段
        console.log(resp)
    })
})

命令行執行:node read_file.js,運行 read_file.js 文件,發現這個 Promise 實例會被立即執行,這是因為 每當 new 一個 Promise 實例的時候,就會立即 執行這個 異步操作中的代碼

要想不立即執行,而是需要的時候再調用,可以將其封裝到函數中:

function readFile(file_path) {
    var promise = new Promise(function () {
        fs.readFile(file_path, 'utf-8', (err, resp) => {
            if (err) throw err
            // if (err) throw err      // 若讀寫文件有錯,則 throw 掉,不執行這段
            console.log(resp)
        })
    })
    
}

readFile('./files/1.txt')

四、通過 then 指定回調

異步操作不能直接 return 獲取執行結果,而是需要通過回調函數獲取,Promise 中可以通過 .then() 來指定回調。

const fs = require('fs')

function getFile(file_path) {
    var promise = new Promise(function (resolve, reject) {
        fs.readFile(file_path, 'utf-8', (err, resp) => {
            if (err) return reject(err)     // 失敗的回調
            
            // 成功的回調
            resolve(resp)
        })
    })

    return promise
}

var p = getFile('./files/1.txt')

// 預先指定回調
p.then(function(resp) {
    // 執行成功
    console.log('執行成功:', resp)
}, function(err) {
    // 執行失敗
    console.log('執行失敗:', err)
})

這里將 promise 實例對象返回,再用一個變量 p 接收,通過 p 調用 then() 方法從而預先指定回調;讀取文件這個異步操作不會立即執行,而是等 then() 指定了回調后才執行。

也可以省略接收變量,直接調用 then()

function getFile(file_path) {
    return new Promise(function (resolve, reject) {
        fs.readFile(file_path, 'utf-8', (err, resp) => {
            if (err) return reject(err)     // 失敗的回調
            
            // 成功的回調
            resolve(resp)
        })
    })

}

getFile('./files/1.txt')
  .then(function(resp) {
      // 執行成功
      console.log('執行成功:', resp)
  }, function(err) {
      // 執行失敗
      console.log('執行失敗:', err)
  })

五、promise 解決回調地獄問題

以此讀取三個文件,出現的回調地獄問題:

const fs = require('fs')


function getFile(file_path) {
    return new Promise(function (resolve, reject) {
        fs.readFile(file_path, 'utf-8', (err, resp) => {
            if (err) return reject(err)     // 失敗的回調
            
            // 成功的回調
            resolve(resp)
        })
    })

}

getFile('./files/1.txt')
    .then(function(resp1) {
        // 執行成功
        console.log('1.txt 執行成功:', resp1)

        getFile('./files/2.txt')
            .then(function(resp2) {
                console.log('2.txt 執行成功:', resp2)

                getFile('./files/3.txt')
                    .then(function(resp3) {
                        console.log('3.txt 執行成功:', resp3)
                    })
            })
    })

promise 解決回調地獄

getFile('./files/1.txt')
    .then(function(resp1) {
        console.log('1.txt 執行成功:', resp1)

        return getFile('./files/2.txt')
    })
    .then(function(resp2) {
        console.log('2.txt 執行成功:', resp2)

        return getFile('./files/3.txt')
    })
    .then(function(resp3) {
        console.log('3.txt 執行成功:', resp3)
    })

promise 采用的是鏈式調用,而不是嵌套調用。

同時指定異常回調:

getFile('./files/1.txt')
    .then(function(resp1) {
        console.log('1.txt 執行成功:', resp1)

        return getFile('./files/2.txt')
    }, function(err1) {
        console.log('讀取 1.txt 出錯:', err1)
    })
    .then(function(resp2) {
        console.log('2.txt 執行成功:', resp2)

        return getFile('./files/3.txt')
    })
    .then(function(resp3) {
        console.log('3.txt 執行成功:', resp3)
    })

注意:異常回調通常可省略!

六、捕獲 promise 中的異常

當有多個 promise "嵌套使用" 出現異常時,通常會有以下兩種處理情形:

  • 前面的 promise 出現異常,不影響后續的 promise 執行:通常給每個 promise 指定異常回調
  • 前面的 promise 一旦出現異常,直接捕獲異常,后續的 promise 不執行:通常使用 catch() 捕獲異常

情形一

// 不存在的文件
getFile('./files/11.txt')
    .then(function(resp1) {
        console.log('1.txt 執行成功:', resp1)

        return getFile('./files/2.txt')
    }, function(err1) {
        console.log('讀取 1.txt 出錯:', err1)
    })
    .then(function(resp2) {
        console.log('2.txt 執行成功:', resp2)

        return getFile('./files/3.txt')
    }, function(err2) {
        console.log('讀取 2.txt 出錯:', err2)
    })
    .then(function(resp3) {
        console.log('3.txt 執行成功:', resp3)
    }, function(err3) {
        console.log('讀取 3.txt 出錯:', err3)
    })

運行 node read_file.js,運行結果:

> node "03. promise 解決回調地獄問題.js"
讀取 1.txt 出錯: [Error: ENOENT: no such file or directory, open 'F:\200-源碼\342-Vue.js\黑馬205集-Vue.js\Vue.js 練習\day08\files\11.txt'] {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'open',
  path: 'F:\\200-源碼\\342-Vue.js\\黑馬205集-Vue.js\\Vue.js 練習\\day08\\files\\11.txt'
}
2.txt 執行成功: undefined
3.txt 執行成功: 333

情形二

getFile('./files/11.txt')
    .then(function(resp1) {
        console.log('1.txt 執行成功:', resp1)

        return getFile('./files/2.txt')
    })
    .then(function(resp2) {
        console.log('2.txt 執行成功:', resp2)

        return getFile('./files/3.txt')
    })
    .then(function(resp3) {
        console.log('3.txt 執行成功:', resp3)
    })
    .catch(function (err) {
        console.log('執行異常::', err.message)
    }) 

console.log('OK')

運行結果:

OK
> node "03. promise 解決回調地獄問題.js"
執行異常:: ENOENT: no such file or directory, open 'F:\200-源碼\342-Vue.js\黑馬205集-Vue.js\Vue.js 練習\day08\files\11.txt'

注意:當 promise 中發生異常時,不會影響主程序后續的程序運行,上述代碼中,會先執行 console.log("OK")

七、Ajax 中使用 promise

$(function () {
      $('#btn').on('click', function () {
        $.ajax({
          url: './data.json',
          type: 'get',
          dataType: 'json'
        })
          .then(function (data) {
            console.log(data)
          })
      })
    });

去掉原有的 success(resp),而是使用 then() 來處理 ajax 請求響應。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM