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 请求响应。

posted @ 2020-09-03 22:43  Hubery_Jun  阅读(3560)  评论(0编辑  收藏  举报