• 【JavaScript】Promise(二) —— 几个关键问题


    系列文章目录

    【JavaScript】Promise(零) —— 准备工作(实例对象、函数对象、回调函数分类、捕获抛出错误)

    【JavaScript】Promise(一) —— 理解和使用(是什么、怎么使用、与 Ajax 配合使用、涉及的API)

    【JavaScript】Promise(二) —— 几个关键问题

    【JavaScript】Promise(三) —— async 与 await、宏任务与微任务



    一、几个关键问题

    1. 如何改变一个 Promise 实例的状态
    1. 执行 resolve(value):如果当前是 pending 就会变为 fulfilled。
    2. 执行 reject(reason):如果当前是 pending 就会变为 rejected。
    3. 执行器函数 (executor) 抛出异常:如果当前是 pending 就会变为 rejected。

    引擎抛异常:

    	const p = new Promise((resolve, reject)=>{
            console.log(a); //引擎抛异常
        })
        p.then(
            value => {console.log('成功了', value);},
            reason => {console.log('失败了', reason);}
        )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    编码抛异常:

    	const p = new Promise((resolve, reject)=>{
            throw -100  //编码抛异常
        })
        p.then(
            value => {console.log('成功了', value);},
            reason => {console.log('失败了', reason);}
        )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    2. 改变 Promise 实例的状态和指定回调函数谁先谁后?
    1. 如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据。
    2. 如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据。

    先指定回调,后改变状态:

        const p = new Promise((resolve, reject)=>{
            setTimeout(()=>{
                resolve(100)
            }, 1000)
        })
    
        p.then(
            value => {console.log('成功了', value);},
            reason => {console.log('失败了', reason);}
        )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述
    先改状态,后指定回调:

        const p = new Promise((resolve, reject)=>{
            resolve('a')
        })
        setTimeout(()=>{
            p.then(
                value => {console.log('成功了', value);},
                reason => {console.log('失败了', reason);}
            )
        }, 1000)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    3. Promise实例.then返回的是一个【新的Promise实例】,它的值和状态由什么决定?
    1. 简单表达:由 then 所指定的回调函数执行的结果决定。
    2. 详细表达:
      (1)如果 then 所指定的回调返回的是非 Promise 值 a,那么【新Promise实例】状态为:成功(fulfilled),成功的 value 为 a。
      (2)如果 then 所指定的回调返回的是一个 Promise 实例 p,那么【新Promise实例】的状态、值,都与 p 一致。
      (3)如果then所指定的回调抛出异常:那么【新Promise实例】状态为 rejected,reason 为抛出的那个异常。
    	const p = new Promise((resolve, reject)=>{
            setTimeout(()=>{
                resolve('a')
            }, 1000)
        })
        const x = p.then(
            value => {console.log('成功了1', value); return 900},
            reason => {console.log('失败了1', reason);}
        )
        x.then(
            value => {console.log('成功了2', value);},
            reason => {console.log('失败了2', reason);}
        )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    then的链式调用:

    	const p = new Promise((resolve, reject)=>{
            setTimeout(()=>{
                resolve('a')
            }, 1000)
        })
        p.then(
            value => {console.log('成功了1', value); return Promise.reject('b')},
            reason => {console.log('失败了1', reason);}
        ).then(
            value => {console.log('成功了2', value); return true},
            reason => {console.log('失败了2', reason); return 100}
        ).then(
            value => {console.log('成功了3', value); throw 900},
            reason => {console.log('失败了3', reason); return false}
        ).then(
            value => {console.log('成功了4', value); return 200},
            reason => {console.log('失败了4', reason);}
        )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    4. Promise如何串连多个异步任务?

    通过 then 的链式调用

    实例:发送三次请求,每次请求成功后再发下一次请求。

    	// 封装ajax请求
        function sendAjax(url) {
            return new Promise((resolve, reject) => {
                // 实例xhr
                const xhr = new XMLHttpRequest()
                // 绑定监听
                xhr.onreadystatechange = () => {
                    if (xhr.readyState === 4) {
                        if (xhr.status >= 200 && xhr.status < 300) {
                            resolve(xhr.response);
                        } else {
                            reject('请求出了点问题');
                        }
                    }
                }
                xhr.open('GET', url)
                xhr.responseType = 'json'
                xhr.send()
            })
        }
    	
    	// 发送第1次请求
    	sendAjax('https://api.apiopen.top/api/sentences')
        .then(
            value => {
                console.log('第1次请求成功了', value);
                return sendAjax('https://api.apiopen.top/api/sentences')
            },
            reason => {
                console.log('第1次请求失败了', reason);
            }
        )
        .then(
            value => {
                console.log('第2次请求成功了', value);
                return sendAjax('https://api.apiopen.top/api/sentences')
            },
            reason => {
                console.log('第2次请求失败了', reason);
            }
        )
        .then(
            value => {
                console.log('第3次请求成功了', value);
            },
            reason => {
                console.log('第3次请求失败了', reason);
            }
        )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    then的链式调用,依次请求成功:

    在这里插入图片描述

    5. 中断 promise 链
    1. 当使用 promise 的 then 链式调用时,在中间中断,不再调用后面的回调函数。
    2. 办法:在失败的回调函数中返回一个 pendding 状态的 Promise 实例。

    在失败的回调中返回 pendding 状态的 Promise 实例

    	return new Promise(() => {})
    
    • 1

    实例:

    	// 封装ajax请求
    	function sendAjax(url) {
    	    return new Promise((resolve, reject) => {
    	        // 实例xhr
    	        const xhr = new XMLHttpRequest()
    	        // 绑定监听
    	        xhr.onreadystatechange = () => {
    	            if (xhr.readyState === 4) {
    	                if (xhr.status >= 200 && xhr.status < 300) {
    	                    resolve(xhr.response);
    	                } else {
    	                    reject('请求出了点问题');
    	                }
    	            }
    	        }
    	        xhr.open('GET', url)
    	        xhr.responseType = 'json'
    	        xhr.send()
    	    })
    	}
    	// 发送第1次请求
    	sendAjax('https://api.apiopen.top/api/sentences')
        .then(
            value => {
                console.log('第1次请求成功了', value);
                return sendAjax('https://api.apiopen.top/api/sentences2')
            },
            reason => {
                console.log('第1次请求失败了', reason);
                return new Promise(() => {})
            }
        )
        .then(
            value => {
                console.log('第2次请求成功了', value);
                return sendAjax('https://api.apiopen.top/api/sentences')
            },
            reason => {
                console.log('第2次请求失败了', reason);
                return new Promise(() => {})
            }
        )
        .then(
            value => {console.log('第3次请求成功了', value);},
            reason => {
                console.log('第3次请求失败了', reason);
                return new Promise(() => {})
            }
        )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    在这里插入图片描述

    6. promise 的错误穿透
    1. 当使用 promise 的 then 链式调用时,可以在最后用 catch 指定一个失败的回调
    2. 前面任何操作出了错误,都会传到最后失败的回调中处理了
    3. 如果不存在 then 的链式调用,就不需要考虑 then 的错误穿透

    使用定时器:

    	const p = new Promise((resolve, reject)=>{
            setTimeout(()=>{
                reject(-1)
            }, 500)
        })
        p.then(
            value => {console.log('成功了1', value);}
        )
        .then(
            value => {console.log('成功了2', value);}
        )
        .catch(
            reason => {console.log('失败了', reason);}
        )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    发送 Ajax 请求:

        // 封装ajax请求
        function sendAjax(url, index) {
            return new Promise((resolve, reject) => {
                // 实例xhr
                const xhr = new XMLHttpRequest()
                // 绑定监听
                xhr.onreadystatechange = () => {
                    if (xhr.readyState === 4) {
                        if (xhr.status >= 200 && xhr.status < 300) {
                            resolve(xhr.response);
                        } else {
                            reject(`${index}次请求出了点问题`);
                        }
                    }
                }
                xhr.open('GET', url)
                xhr.responseType = 'json'
                xhr.send()
            })
        }
    	
    	sendAjax('https://api.apiopen.top/api/sentences', 1)
            .then(
                value => {
                    console.log('第1次请求成功了', value);
                    return sendAjax('https://api.apiopen.top/api/sentences2', 2)
                },
            )
            .then(
                value => {
                    console.log('第2次请求成功了', value);
                    return sendAjax('https://api.apiopen.top/api/sentences', 3)
                },
            )
            .then(
                value => {
                    console.log('第3次请求成功了', value);
                },
            )
            .catch(
                reason => {
                    console.log('失败了', reason);
                }
            )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    在这里插入图片描述

    不积跬步无以至千里,不积小流无以成江海

    点个关注不迷路,持续更新中…

  • 相关阅读:
    使用uncompyle6反编译pyc文件(附报KeyError和Error: uncompyle6 requires Python 2.6-3.8的解决方法)
    Unity之ShaderGraph如何实现积雪效果
    el-form表单动态校验(场景: 输入框根据单选项来动态校验表单 没有选中的选项就不用校验)
    1万属性,100亿数据,每秒10万吞吐,架构如何设计?
    文件判空工具类
    稳压二极管的应用及注意事项
    Nginx设置Https
    百度地图实现热力图的添加、移除
    mysql外键(foreign key)
    element-ui+vue上传图片和评论现成完整html页面
  • 原文地址:https://blog.csdn.net/qq_45902692/article/details/125637613