前端Promise学习记录

95 阅读3分钟

前端Promise学习记录

自我提问:

  1. 什么是异步编程,为什么要有这个东西?
  2. 在 Promise 之前,是靠什么来解决问题的?

Promise 介绍与基本使用

功能说明:Promise 对象用来封装一个异步操作并可以获取其 成功 / 失败 的结果

优势

  • 通过链式调用,解决回调地狱问题
  • 指定回调函数的方式更加灵活

初体验

写一个抽奖demo

function rand(m,n){
            return Math.ceil(Math.random() * (n-m+1) ) + m - 1
        }
        const btn = document.getElementById('btn')
        btn.onclick = () => {
            // // 定时器
            // setTimeout(() => {
            //     let n = rand(1,100)
            //     if (n <= 30) {
            //         alert('恭喜中奖!')
            //     } else {
            //         alert('再接再厉!')
            //     }
            // }, 1000)

            // Promise 形式  
            const p = new Promise((resolve, reject) => {
                setTimeout(() => {
                    let n = rand(1,100)
                    console.log(n)
                    if (n <= 30) {
                        resolve(n)
                    } else {
                        reject(n)
                    }
                }, 1000)
            })

            p.then((value) => {
                alert('恭喜中奖!' + value)
            }, (reason) => {
                alert('再接再厉!' + reason)
            })
        }

Promise实践练习-fs模块

let p = new Promise((resolve, reject) => {
    fs.readFile('./content.tx', (err, data) => {
        // 抛出错误
        if (err) reject(err)
        resolve(data)
    })
})

p.then(value => {
    console.log(value.toString())
}, reason => {
    console.log(reason)
})

进一步封装

/**
 * 封装一个 mineReadFile 读取文件内容
 * 参数: path 文件路径
 * 返回: promise 对象
 */
function mineReadFile(path) {
    return new Promise((resolve, reject) => {
        require('fs').readFile(path, (err, data) => {
            if (err) reject(err)
            resolve(data)
        })
    })
}

mineReadFile('./content.txt').then(value => {
    console.log(value.toString())
}, reason => {
    console.log(reason)
})

Promise实践练习-AJAX请求

/**
* 封装一个函数 sendAJAX 发送 GET 请求
* 参数: URL
* 返回: Promise 对象
*/
function sendAJAX(url) {
return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.responseType = 'json'
    xhr.open('GET', url)
    xhr.send()
    xhr.onreadystatechange = () => {
        if (xhr.readyState === 4 ) {
            if (xhr.status >= 200 && xhr.status < 300) {
                resolve(xhr.response)
            } else {
                reject(xhr.status)
            }
        }
    }
})
}

sendAJAX('https://api.apiopen.top/getJoke').then(value => {
    console.log(value)
}, reason => {
    console.warn(reason)
})

util.promisify 方法

可以自动把一个函数封装成一个Promise对象

const fs =require('fs')
let mineReadFile = require('util').promisify(fs.readFile)

mineReadFile('./content.txt').then(value => {
    console.log(value.toString())
}, reason => {
    console.log(reason)
})

Promise 的状态

PromiseState

  • pending 未决定的
  • resolved / fullfilled 成功
  • rejected 失败 PromiseResult 异步对象成功/失败的结果 resolve/reject 可以对其赋值

Promise API

Promise(excutor){}

executor 会在Promise 内部立即同步调用,异步操作在执行器中执行(?没理解)

Promise.all 方法 (promises) => {}

接收promise数组,返回一个新的promise,只有当所有promise都成功时才成功,否则失败。

成功时返回的promise的result为一个数组,包含所有成功的值。

失败时返回第一个失败的结果

Promise.race 方法

返回第一个改变状态的promise

Promise 关键问题

如何修改对象的状态

  • 调用resolve 函数
  • 调用reject 函数
  • 抛出错误,throw 'error'

能否执行多个回调

可以,一个promise可以有多个p.then()

Promise状态先改变还是先指定回调

Promise.then() 的返回结果是由什么决定的

  • 抛出错误,则返回的是失败的promise
  • return 非 Promise 类型的对象,则返回一个成功的Promise,值为return的结果,如果没有return,则为undefined
  • return Promise,则继承状态与值

Promise 如何串联多个操作任务

正是由于前一个问题的机制,Promise.then()返回的是一个Promise,所以能够进行链式调用,避免了回调地狱。

Promise 的异常穿透

概念:一条Promise.then()的链式调用,只需要在最后写一个失败的回调即可,这就是异常穿透

中断 Promise 链

如果只是抛出错误之类的方式,整个Promise链条的各个回调依然会继续执行下去,若要直接强行中断,需要返回一个pending的Promise,如return new Promise(()) => {}

Promise 自定义封装

跟着老师手写了一遍 Promise ,写完后感觉非常好,一是再一次锻炼了自己的 JavaScript 水平,二是能够从原理上理解 Promise 是怎么工作的,在应用的时候也能更有自信去把控它。强烈建议大家去手写一遍,同时也认识到这种学习方式也适用于其他地方。

async 与 await

没学之前以为这个很高端,看不懂,学了后发现无非就是一个 Promise 的语法糖而言...让我们写 Promise 更快一点。

这两个都是JS的关键字,async 用于标识一个函数为异步函数,await 用于直接提取到该异步函数的 response,从这里也能够看出,await 必须写在 async 里面。

总结

学得很开心,收获很多。我们要再接再厉。