侧边栏壁纸
博主头像
GabrielxD

列車は必ず次の駅へ。では舞台は?私たちは?

  • 累计撰写 675 篇文章
  • 累计创建 128 个标签
  • 累计收到 22 条评论

目 录CONTENT

文章目录

【学习笔记】Promise(JavaScript)

GabrielxD
2022-02-19 / 0 评论 / 0 点赞 / 272 阅读 / 2,533 字
温馨提示:
本文最后更新于 2022-07-26,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

Promise 的理解和使用

Promise 是什么?

理解

  • 抽象表达:

    1. Promise 是一门新的技术(ES6 规范)
    2. Promise 是 JS 中进行异步编程的新解决方案(旧方案是单纯使用回调函数)
  • 具体表达:

    1. 从语法上来说: Promise 是一个构造函数
    2. 从功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值

promise 的状态改变

  1. pending 变为 resolved
  2. pending 变为 rejected

说明: 只有这 2 种,且一个 promise 对象只能改变一次,无论变为成功还是失败,都会有一个结果数据,成功的结果数据一般称为 value, 失败的结果数据一般称为 reason。

promise 的基本流程

image-20220218015043292

promise 的基本使用

使用 1: 基本编码流程

<script>
    // 1) 创建 promise 对象(pending 状态), 指定执行器函数
    const p = new Promise((resolve, reject) => {
        // 2) 在执行器函数中启动异步任务
        setTimeout(() => {
            const time = Date.now()
            // 3) 根据结果做不同处理
            if (time%2===1) {
                // 3.1) 如果成功了, 调用 resolve(), 指定成功的 value, 变为 resolved 状态
                resolve('成功的值 '+ time)
            } else {
                // 3.2) 如果失败了, 调用 reject(), 指定失败的 reason, 变为 rejected 状态
                reject('失败的值' + time)
            }
        }, 2000)
    }
// 4) 能 promise 指定成功或失败的回调函数来获取成功的 vlaue 或失败的 reason
	p.then(value => { // 成功的回调函数 onResolved, 得到成功的 vlaue
		console.log('成功的 value: ', value)
    }, reason => { // 失败的回调函数 onRejected, 得到失败的 reason
		console.log('失败的 reason: ', reason)
	});
</script>

使用 2: 使用 promise 封装读取文件的异步

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

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

使用 3: 使用 promise 封装 ajax 异步请求

<script>
    const sendAJAX = function (url) {
        return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            xhr.responseType = 'json';
            xhr.open('GET', url);
            xhr.send();
            xhr.onreadystatechange = function () {
                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.log(reason);
});
</script>

为什么要用 Promise?

1、指定回调函数的方式更加灵活

  • 以前: 必须在启动异步任务前指定
  • promise: 启动异步任务 => 返回promie对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定/多个)

2、支持链式调用, 可以解决回调地狱问题

  • 回调地狱: 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件
  • 回调地狱的缺点: 不便于阅读 不便于异常处理
  • 解决方案: promise 链式调用
  • 终极解决方案: async/await

image-20220218020103188

如何使用 Promise?

Promise 构造函数:

Promise (excutor) {}
  • executor 函数: 执行器 (resolve, reject) => {}
    • resolve 函数: 内部定义成功时调用的函数: value => {}
    • reject 函数: 内部定义失败时调用的函数: reason => {}

说明: executor 会在 Promise 内部立即同步调用,异步操作在执行器中执行

Promise API

Promise.prototype.then
Promise.prototype.then(onResolved, onRejected) => {}
  • onResolved 函数: 成功的回调函数: (value) => {}
  • onRejected 函数: 失败的回调函数: (reason) => {}

说明: 指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调,返回一个新的 promise 对象

Promise.prototype.catch
Promise.prototype.catch(onRejected) => {}
  • onRejected 函数: 失败的回调函数: (reason) => {}

说明: then() 的语法糖, 相当于: then(undefined, onRejected)

Promise.resolve
Promise.resolve(value) => {}
  • value: 成功的数据或 promise 对象

说明: 返回一个成功/失败的 promise 对象

Promise.reject
Promise.reject(reason) => {}
  • reason: 失败的原因

说明: 返回一个失败的 promise 对象

Promise.all
Promise.all(promises) => {}
  • promises: 包含 n 个 promise 的数组

说明: 返回一个新的 promise, 只有所有的 promise 都成功才成功, 只要有一个失败了就直接失败

Promise.race
Promise.race(promises) => {}
  • promises: 包含 n 个 promise 的数组

说明: 返回一个新的 promise, 第一个完成的 promise 的结果状态就是最终的结果状态

promise 的几个关键问题

1、如何改变 promise 的状态?
  1. resolve(value): 如果当前是 pending 就会变为 resolved
  2. reject(reason): 如果当前是 pending 就会变为 rejected
  3. 抛出异常: 如果当前是 pending 就会变为 rejected
2、一个 promise 指定多个成功/失败回调函数, 都会调用吗?

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

3、改变 promise 状态和指定回调函数谁先谁后?
  • 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
    • 如何先改状态再指定回调?
      1. 在执行器中直接调用 resolve() / reject()
      2. 延迟更长时间才调用 then()
  • 什么时候才能得到数据?
    1. 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
    2. 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
4、promise.then() 返回的新 promise 的结果状态由什么决定?
  • 简单表达: 由 then() 指定的回调函数执行的结果决定
  • 详细表达:
    1. 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
    2. 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值
    3. 如果返回的是另一个新 promise, 此 promise 的结果就会成为新 promise 的结果
5、promise 如何串连多个操作任务?
  1. promise 的 then() 返回一个新的 promise, 可以开成 then() 的链式调用
  2. 通过 then 的链式调用串连多个同步/异步任务
6、promise 异常传透?
  • 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调,
  • 前面任何操作出了异常, 都会传到最后失败的回调中处理
7、中断 promise 链?
  • 当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数
  • 办法: 在回调函数中返回一个 pendding 状态的 promise 对象

手写 Promise

构造函数版

function Promise(executor) {
    this.promiseState = 'pending';
    this.promiseResult = null;
    this.callbacks = [];

    const _this = this;

    // resolve 函数
    function resolve(data) {
        // 判断状态
        if (_this.promiseState !== 'pending') return;
        // 设置对象状态(promiseState)
        _this.promiseState = 'fulfilled';
        // 设置对象结果(promiseResult)
        _this.promiseResult = data;

        // 调用成功的回调函数
        setTimeout(() => {
            _this.callbacks.forEach(item => {
                item.onResolved(data);
            });
        });
    }

    // reject 函数
    function reject(data) {
        // 判断状态
        if (_this.promiseState !== 'pending') return;
        // 设置对象状态(promiseState)
        _this.promiseState = 'rejected';
        // 设置对象结果(promiseResult)
        _this.promiseResult = data;

        // 调用失败的回调函数
        setTimeout(() => {
            _this.callbacks.forEach(item => {
                item.onRejected(data);
            });
        });
    }

    try {
        // 同步调用 执行器函数
        executor(resolve, reject);
    } catch (error) {
        reject(error);
    }
}

Promise.prototype.then = function (onResolved, onRejected) {
    const _this = this;

    // 默认值
    if (typeof onResolve !== 'function') {
        onRejected = value => value;
    }
 
    if (typeof onRejected !== 'function') {
        onRejected = reason => {
            throw reason;
        }
    }

    return new Promise((resolve, reject) => {
        // 封装函数
        function callback(type) {
            try {
                let result = type(_this.promiseResult);
                if (result instanceof Promise) {
                    // 如果是 Promise 类型的对象
                    result.then(v => {
                        resolve(v);
                    }, r => {
                        reject(r);
                    });
                } else {
                    resolve(result);
                }

            } catch (e) {
                reject(e);
            }
        }

        // 调用回调函数
        // 判断 pending 状态
        if (this.promiseState === 'fulfilled') {
            setTimeout(() => {
                callback(onResolved);
            });
        } else if (this.promiseState === 'rejected') {
            setTimeout(() => {
                callback(onRejected)
            });
        } else if (this.promiseState === 'pending') {
            // 保存回调函数
            this.callbacks.push({
                onResolved() {
                    callback(onResolved);
                },
                onRejected() {
                    callback(onRejected);
                }
            });
        }
    });
}

Promise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected);
}

Promise.resolve = function (value) {
    return new Promise((resolve, reject) => {
        if (value instanceof Promise) {
            value.then(v => {
                resolve(v);
            }, r => {
                reject(r);
            });
        } else {
            resolve(value);
        }
    });
}

Promise.reject = function (value) {
    return new Promise((resolve, reject) => {
        reject(value);
    });
}

Promise.all = function (promises) {
    return new Promise((resolve, reject) => {
        const values = [];
        const hasReject = false;

        for (let i in promises) {
            promises[i].then(v => {
                values[i] = v;
            }, r => {
                reject(r);
                hasReject = true;
            });
        }
        if (!hasReject) resolve(values);
    });
}

Promise.race = function (promises) {
    return new Promise((resolve, reject) => {
        for (let i in promises) {
            promises[i].then(v => {
                resolve(v);
            }, r => {
                reject(r);
            });
        }
    });
}

class 版

class Promise {
    #promiseState = 'pending';
    #promiseResult = null;
    #callbacks = [];

    // 构造方法
    constructor(executor) {
        // resolve 函数
        const resolve = data => {
            // 判断状态
            if (this.#promiseState !== 'pending') return;
            // 设置对象状态(#promiseState)
            this.#promiseState = 'fulfilled';
            // 设置对象结果(#promiseResult)
            this.#promiseResult = data;

            // 调用成功的回调函数
            setTimeout(() => {
                this.#callbacks.forEach(item => {
                    item.onResolved(data);
                });
            });
        }

        // reject 函数
        const reject = data => {
            // 判断状态
            if (this.#promiseState !== 'pending') return;
            // 设置对象状态(#promiseState)
            this.#promiseState = 'rejected';
            // 设置对象结果(#promiseResult)
            this.#promiseResult = data;

            // 调用失败的回调函数
            setTimeout(() => {
                this.#callbacks.forEach(item => {
                    item.onRejected(data);
                });
            });
        }

        try {
            // 同步调用 执行器函数
            executor(resolve, reject);
        } catch (error) {
            reject(error);
        }
    }

    then(
        onResolved = value => value, /* ES6默认值 */
        onRejected = reason => { throw reason; }
    ) {
        return new Promise((resolve, reject) => {
            // 封装函数
            const callback = type => {
                try {
                    let result = type(this.#promiseResult);
                    if (result instanceof Promise) {
                        // 如果是 Promise 类型的对象
                        result.then(v => {
                            resolve(v);
                        }, r => {
                            reject(r);
                        });
                    } else {
                        resolve(result);
                    }

                } catch (e) {
                    reject(e);
                }
            }

            // 调用回调函数
            // 判断 pending 状态
            if (this.#promiseState === 'fulfilled') {
                setTimeout(() => {
                    callback(onResolved);
                });
            } else if (this.#promiseState === 'rejected') {
                setTimeout(() => {
                    callback(onRejected)
                });
            } else if (this.#promiseState === 'pending') {
                // 保存回调函数
                this.#callbacks.push({
                    onResolved() {
                        callback(onResolved);
                    },
                    onRejected() {
                        callback(onRejected);
                    }
                });
            }
        });
    }

    catch(onRejected) {
        return this.then(undefined, onRejected);
    }

    static resolve(value) {
        return new Promise((resolve, reject) => {
            if (value instanceof Promise) {
                value.then(v => {
                    resolve(v);
                }, r => {
                    reject(r);
                });
            } else {
                resolve(value);
            }
        });
    }

    static reject(value) {
        return new Promise((resolve, reject) => {
            reject(value);
        });
    }

    static all(promises) {
        return new Promise((resolve, reject) => {
            const values = [];
            const hasReject = false;

            for (let i in promises) {
                promises[i].then(v => {
                    values[i] = v;
                }, r => {
                    reject(r);
                    hasReject = true;
                });
            }
            if (!hasReject) resolve(values);
        });
    }

    static race(promises) {
        return new Promise((resolve, reject) => {
            for (let i in promises) {
                promises[i].then(v => {
                    resolve(v);
                }, r => {
                    reject(r);
                });
            }
        });
    }
}

async & await

MDN 文档

async函数 - JavaScript | MDN

await - JavaScript | MDN

async 函数

  • 函数的返回值为 promise 对象
  • promise 对象的结果由 async 函数执行的返回值决定

await 表达式

  • await 右侧的表达式一般为 promise 对象, 但也可以是其它的值
  • 如果表达式是 promise 对象, await 返回的是 promise 成功的值
  • 如果表达式是其它值, 直接将此值作为 await 的返回值

注意

  • await 必须写在 async 函数中, 但 async 函数中可以没有 await
  • 如果 await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理
0

评论区