重学前端2022之Promise

1.Promise是什么

Promise是JS处理异步编程的一种解决方案。从语法上看,Promise是一个构造函数;从功能上看,可以用来封装一个异步操作并且可以获取其成功/失败的结果值。

常见的异步编程: fs文件操作、Ajax、定时任务

  1. fs文件操作

(1) 回调函数形式:

// 引入fs模块
const fs = require('fs')
fs.readFile('./context.txt', (err, data) => {
    // 如果出错,抛出异常
    if(err) throw err
    // 否则输出文件内容
    console.log(data.toString());
})

(2)promise实现:

// 引入fs模块
const fs = require('fs')

const p = new Promise((resolve, reject) => {
    fs.readFile('./context.txt', (err, data) => {
        if(err) reject(err)
        resolve(data)
    })
})
p.then(res => {
    console.log(res.toString());
}, err => {
    console.log(err);
})

(3)封装fs模块:

function myReadFile(path) {
    // 读取文件
    return new Promise((resolve, reject) => {
        // 读取文件
        require('fs').readFile(path, (err, data) => {
            // 判断 
            if(err) reject(err)
            resolve(data)
        })
    })
}

myReadFile('./context.txt').then(res => {
    console.log(res.toString());
}, err => {
    console.log(err);
})
  1. Ajax

(1) promie实现:

<body>
    <div>
        <p>Promis封装Ajax</p>
        <button class="btn">发送Ajax请求</button>
    </div>
    <script>
        // 获取元素
        const btn = document.querySelector('.btn')
        // 绑定事件
        btn.addEventListener('click', function(){
            // 创建promise
            const p = new Promise((resolve, reject) => {
                // 创建xhr对象
                const xhr = new  XMLHttpRequest()
                // 初始化连接
                xhr.open('GET', 'http://localhost:3000/person')
                // 发送请求
                xhr.send()
                // 处理响应结果
                xhr.onreadystatechange = function() {
                    if(xhr.readyState === 4) {
                        // 判断响应状态码
                        if(xhr.status >= 200 && xhr.status < 300) {
                            resolve(xhr.response)
                        } else {
                            reject(xhr.status)
                        }
                    }
                }
            })
            // 调用then
            p.then(res => {
                console.log(res);
            }, err => {
                console.log(err);
            })
        })
    </script>
</body>

(2)封装ajax:

function sendAjax(path) {
    // 创建promise
    return new Promise((resolve, reject) => {
        // 创建xhr对象
        const xhr = new XMLHttpRequest()
        // 初始化
        xhr.open('GET', path)
        // 响应体类型
        xhr.responseType = 'json';
        // 发送请求
        xhr.send()
        // 处理响应结果
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
            // 判断响应状态码
           if (xhr.status >= 200 && xhr.status < 300) resolve(xhr.response)
                reject(xhr.status)
            }
        }
    })
}

sendAjax('http://localhost:3000/person').then(res => {
    console.log(res);
}, err => {
    console.log(err);
})
  1. 定时任务

2.为什么要使用Promise

  1. 支持链式调用,可以解决回调地狱问题
  • 什么是回调地狱?
    回调函数的嵌套使用,外部回调函数异步执行的结果是嵌套的回调执行的条件。
  • 回调地狱的缺点?
    不便于阅读;不便于异常处理
  • 解决方案?
    promise的链式调用
  • 终极解决方案?
    aync/await
  1. 指定回调函数的方式更灵活
  • 旧的方式: 必须在启动异步任务前指定。
  • promise:启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定多个)

3.Promise的执行流程

在这里插入图片描述

4.Promise的使用

4.1 Promise构造函数:Promise(excutaor) {}

  • excutor函数:执行器,(resolve, reject) => {},excutor会在Promise内部立即同步执行,异步操作在执行器中执行;
  • resolve函数:内部定义成功时调用的函数data => {};
  • reject函数: 内部定义失败时调用的函数err => {}。

4.2 Promise.prototype.then方法:(onResolved, onrejected) => {}

  • onResolved函数:成功的回到函数data => {};
  • onRejected函数:失败的回调函数err => {}。
  • 指定用于得到成功data的成功回调和用于的得到失败err的失败回调都是返回一个新的promise对象。
let p = new Promise((resolve, reject) => {
    resolve('suceess')
    // reject('error')
})
console.log('p-suceess', p); // Promise {<fulfilled>: 'suceess'}
// console.log('p-error', p); // Promise {<rejected>: 'error'}
p.then(res => {
    console.log('onResolve', res);
}, err => {
    console.log('onReject', err);
})

4.3 Promise.prototype.catch方法: (onRejected) = {}

  • onRejected函数:失败的回调函数err => {};
  • then()的语法糖,相当于:then(undefined, onReject)
let p = new Promise((resolve, reject) => {
    reject('error')
})
console.log('p', p) // Promise {<rejected>: 'error'}
p.catch(err => {
    console.log('catch', err);
})

// 相当于:
// p.then(undefined, err => {
//     console.log(err);
// })

4.4 Promise.resolve方法: (data) => {}

  • data:成功的数据或promise对象;
  • 结果返回一个成功/失败的promise对象。
// 传入的值为非promise对象,则返回的结果为resolve的promise对象
let p1 = Promise.resolve(111)
console.log('p1', p1); // Promise {<fulfilled>: 111}
// 传入的值为promise对象,由传入的参数结果决定resolve的结果
let p2 = Promise.resolve(new Promise((resolve, reject) => {
    resolve(222)
    // reject(333)
}))
console.log('p2-resolv', p2); // Promise {<fulfilled>: 222}
// console.log('p2-reject', p2);  // Promise {<rejected>: 333}
p2.catch(err => {
        console.log(err);
})

4.5 Promise.reject方法: (err) => {}

  • err: 失败的原因;
  • 返回一个失败的promise对象。
let p = Promise.reject('error')
console.log('p', p); // Promise {<rejected>: 'error'}
p.catch(err => {
    console.log(err);
})
let p2 = Promise.reject(new Promise((reslove, reject) => {
    reslove(111)
}))
console.log('p2', p2); // Promise {<rejected>: Promise}
p2.catch(err => {
    console.log(err);
})

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

  • promises: 包含n个promise的数组;
  • 返回一个新的promise,只有所有的promise都成功才成功,否则只要有一个失败了就直接失败。
let p1 = Promise.resolve(111)
let p2 = Promise.resolve(222)
let p3 = Promise.resolve(333)
let p4 = Promise.reject(444)
const result1 = Promise.all([p1, p2, p3])
console.log(result1);
// result1的打印结果:
// Promise {<pending>}
// [[Prototype]]: Promise
// [[PromiseState]]: "fulfilled"
// [[PromiseResult]]: Array(3)
// 0: 111
// 1: 222
// 2: 333
// length: 3
// [[Prototype]]: Array(0)

const result2 = Promise.all([p1, p2, p4])
console.log(result2);
// result2的打印结果:
// Promise {<pending>}
// [[Prototype]]: Promise
// [[PromiseState]]: "rejected"
// [[PromiseResult]]: 444
result2.catch(err => { })

4.7 Promise.race方法: (promises) => {}

  • promises:包含n个promise的数组;
  • 返回一个新的promise,第一个完成的promise的结果装填就是最终结果状态。
let p1 = new Promise((resolve, reject) => {
    resolve(111)
})
let p2 = Promise.resolve(222)
let p3 = Promise.reject(333)
let result = Promise.race([p3, p2, p1])
result.catch(err => {})
console.log(result);
// result的打印结果:
// Promise {<pending>}
// [[Prototype]]: Promise
// [[PromiseState]]: "rejected"
// [[PromiseResult]]: 333

5.Promise的关键问题

5.1 如何改变promise的状态?

  • resolve(data): 当前状态由peding -> fullfilled
  • reject(err): 当前状态由pending -> rejected
  • throw抛出异常: 当期状态由peddign -> rejected
let p = new Promise((resolve, reject) => {
    // 1.使用resolve: 状态由pending => fullfilled
    // resolve('success')
    // 2.使用reject: 状态由pending => rejected
    // reject('error')
    // 3.抛出异常: 状态由pending => rejected
    throw '有异常了'
    })
p.catch(err => {
    console.log(err); 
})
// console.log('resolve', p); // Promise {<fulfilled>: 'success'}
// console.log('reject', p); // Promise {<rejected>: 'error'}
console.log('throw', p); // Promise {<rejected>: '有异常了'}

5.2 一个promise指定多个成功/失败回调函数,都会调用吗?

当promise改变为对应状态时都会调用

// promise的状态变为对应的状态都会调用
let p = new Promise((resolve, reject) => {
    resolve('ok')
})
// 指定回调1
p.then(res => {
    console.log('回调1', res); // ok
})
// 回调2
p.then(res => {
    console.log('回调2', res); // ok
})

let p2 = new Promise((resolve, reject) => {
    reject('error')
})
p2.catch(err => {
    console.log(err); // error
})
p2.catch(err => {
     console.log(err); // error
})

5.3 改变promise状态和指定回调函数谁先谁后?

  • 都有可能,正常情况先指定回调再改变状态,但也可以先改变状态再指定回调
  • 如何先改变状态再指定回调?
    在执行器中直接调用resolve()/reject();延迟更长时间调用then()
  • 什么时候才能得到数据?
    如果是先指定回调,当状态发生改变,回调函数就会调用,得到数据;如果是先改变状态,指定回调时,回调函数就会调用,得到数据。

5.4 promise.then()返回的promise的状态由什么决定?

  • 简单表达式由then()指定的回调函数指向的结果决定
  • 详细表达:
    (1)如果返回另一个新的promise,此promise的结果就是新的promise的结果;
    (2)如果返回一个非promise的值,新的promise变为resolved,data就是返回的值;
    (3)如果抛出异常,新的promise变为rejected,err为抛出的异常

5.5 promise如何串连多个操作任务?

promise的then()返回新的promise,所以可以通过then()的链式调用串连多个同步或异步任务

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success')
    })
})
// 通过then()方法来串联多个任务
p.then(res => {
    console.log(res);
}).then(res => {
    console.log(222);
}).then(res => {
    console.log(333);
})

5.6 promise异常穿透

当使用promise的then链式调用时,可以在最后指定失败的回调,前面任何操作出了异常,都会传到最后的回调中处理。

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success')
        // reject('error')
    }, 100)
})
p.then(res => {
    console.log(111);
}).then(res => {
    throw '出错了'
    console.log(222);
}).then(res => {
    console.log(33);
}).catch(err => {
    // 使用catch来指定失败的回调
    console.log(err);
})

5. 7 如何中断promise链?

在回调函数中返回一个pending状态的promise对象。

let p = new Promise((resolve, reject) => {
     resolve('success')
})
p.then(res => {
    console.log(111);  // 111 只有治理打印了
    // 使用状态为pending的promise来中断promise链
    return new Promise((resolve, reject) => {})
}).then(res => {
    console.log(222);
}).then(res => {
    console.log(333);
}).catch(err => {
    console.log(err);
})

6.async和await

  • async函数:该函数返回一个promise对象,promise对象的结果由async函数执行的返回值决定。
async function main() {
    // 1.函数执行返回值是非promise对象
    // return 11
    // 2.返回值是一个promise对象
    // return new Promise((resolve, reject) => {
    //     // reject('error')
    //     resolve('ok')
    // })
    // 抛出异常
    throw 'Error'

}
const result = main()
// console.log('非promise', result);  // 非promise Promise {<fulfilled>: 11}
result.catch(err => { })

// console.log('promise-reject', result);
// // promise - reject 
// // Promise {<pending>}
// //     [[Prototype]]: Promise
// //     [[PromiseState]]: "rejected"
// //     [[PromiseResult]]: "error"

// console.log('promise-resolve', result);
// // promise-resolve 
// //     Promise {<pending>}
// //     [[Prototype]]: Promise
// //     [[PromiseState]]: "fulfilled"
// //     [[PromiseResult]]: "ok"

console.log('throw', result); // throw Promise {<rejected>: 'Error'}
  • await表达式: await右侧的表达式一般为promise对象,也可以是其他值。如果是promise对象,await返回promise成功的值;如果是其他值,直接将其作为await的返回值。
async function main() {
            let p = new Promise((resolve, reject) => {
                // resolve('success')
                reject('error')
            })
            // 1.await右侧为其他类型的数据, 直接将其作为返回值
            // let res = await 22
            // console.log(res); // 22

            // 2.await右侧为promise的情况
            // 2.1成功状态
            // let res2 = await p
            // console.log(res2); // sucess

            // 2.2 失败状态
            try{
                let res3 = await p
            } catch(e) {
                console.log(e);
            }
        }
        main()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值