超详细的Promise系统化学习(1)


前言

为了学习axios请求,不得不再学一遍promise

一、Promise

一种异步操作,针对回调函数,会返回两种结果,一般用于如下1情况:

1.fs文件操作
require('fs').readFile('./....',(err,data)=>{})
2.数据库
3.Ajax
$.get('/server'.(data)=>{})
4.定时器
setTimeout(()=>{},2000)

所以我们为什么要使用Promise??

首先介绍回调地狱(Callback Hell)
回调函数的嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行条件
缺点:不便于阅读,不便于异常处理

用一张网上图片展示回调地狱:
在这里插入图片描述
所以我们可以使用Promise的链式调用解决
基本写法(类似构造函数)

resolve:成功
reject:失败

const p =new Promise((resolve,reject)=>{...})

这里再简单介绍一下Ajax发起请求的四个步骤:
1.创建对象
const xhr=new XMLHttpRequest()
2.初始化
xhr.open('GET','路径')
3.发送
xhr.send()
4.处理响应结果
xhr.onreadystatechange=function(){状态码判断}

二、基本应用

调用构造函数创建,最后分情况讨论

1.定时器相关

<script>
    function rand(m, n) {
        return Math.ceil(Math.random() * (n - m + 1)) + m - 1
    }
    const btn = document.querySelector('#btn')
    btn.addEventListener('click', function () {
        // setTimeout(() => {
        //     var t = rand(1, 100)
        //     if  (t <= 30) {
        //         alert("中奖了")
        //     }
        //     else {
        //         alert("Again")
        //     }
        // }, 1000);
        const p=new Promise((resolve,reject)=>{
            setTimeout(() => {
            var t = rand(1, 100)
            if  (t <= 30) {
                resolve(t)
            }
            else {
                reject(t)
            }
            }, 1000);
        })
        p.then((e)=>{
            alert("中奖!!!"+e)
        },(e)=>{
            alert("Again"+e)
        })
    })
</script>

2.文件操作

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

在这里插入图片描述

3.Ajax请求

那四个步骤,然后包装在Promise中

const btn=document.querySelector('#btn')
     btn.addEventListener("click",function(){
         const p=new Promise((resolve,reject)=>{
            const xhr=new XMLHttpRequest()
         xhr.open('GET','{链接}')
         xhr.send()
         xhr.onreadystatechange=function(){
             if(xhr.readyState===4){
                 if(xhr.state>=200&&xhr.state<300){
                     resolve(xhr.reponse)
                 }
                 else {
                      reject(xhr.status)
                 }
                }
            }
         })
         p.then((response)=>{
             console.log(response)
         },(status)=>{
             console.log(status)
         })
     })

4.封装读取文件函数

const fs=require('fs')
function readAFile(path){
    return new Promise((resolve,reject)=>{
        fs.readFile(path,(err,data)=>{
            if(err) reject(err)
            resolve(data)
        })
    })
}

readAFile('./text.txt').then((data)=>{
    console.log(data.toString())
},(err)=>{
    console.log(err)
})

在这里插入图片描述

5.util.promisify方法

相当于一个将readFile方法promise化,这个方法就类似我们上一块写的函数。

const util=require('util')

const fs=require('fs')

let mineReadFile=util.promisify(fs.readFile)

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

6.封装发送Ajax方法

封装一个sendAjax函数,传入参数url,返回一个Promise对象(样例url自己添加调试)。

    function sendAjax(url) {
        return new Promise((resolve,reject)=>{
            const xhr=new XMLHttpRequest()
            xhr.open('GET',url)
            xhr.send()
            xhr.onreadystatechange=function(){
                if(xhr.readyState===4){
                    if(xhr.state>=200&&xhr.state<300){
                        resolve(xhr.response)
                    }
                    else {
                        reject(xhr.status)
                    }
                }
            }
        })
    }

    sendAjax('').then((response)=>{
        console.log(response)
    },(status)=>{
        console.log(status)
    })

三、Promise状态改变

我们打印一下Promise内部
在这里插入图片描述

1.PromiseState状态

PromiseState就是Promise的当前状态,此处 显示“rejected”

Promise一共含 有三种状态:
1.pending 未决定的,初始
2.resolved /fulfilled 成功
3.rejected 失败
三者关系:
pending->resolved
pending=>rejected
(即未决定可以转成成功和失败,但成功和失败之间是不允许转化的

2.PromiseResult异步任务结果

如上截图的另一个属性

有两种改变其值的方法:
1.resolve
2.reject

四、Promise流程图

(取自网课视频)
在这里插入图片描述

五、Promise-API

then、catch不做叙述

1.resolve

如果传入参数为非promise类型对象–成功

let p1=Promise.resolve(123)
    console.log(p1)

在这里插入图片描述
传入的是promise对象,结果和promise结果一样
如下,传入的Promise对象结果是成功的

 let p2=Promise.resolve(new Promise((resolve,reject)=>{
        resolve("hahahah")
    }))
    console.log(p2)

结果;
在这里插入图片描述
相反:

let p2=Promise.resolve(new Promise((resolve,reject)=>{
        reject("hahahah")
    }))
    console.log(p2)

在这里插入图片描述
我们发现此时报错,这是因为我们结果是失败的却没有做处理,这里可以使用catch进行处理

let p2=Promise.resolve(new Promise((resolve,reject)=>{
        reject("hahahah")
    }))
    // console.log(p2)
    p2.catch((data)=>{
        console.log(data)
    })

2.reject

这个API就是无论你传入什么值,最后返回的也是一个失败的Promise对象,当然如上一个所说,失败的必须要做catch处理,不然报错

    let  p3=Promise.reject(123)
    p3.catch((err)=>{
        console.log(err)
    })

最后打印”123“

3.all

传入的参数是由多个promise组成的数组,只有当这些个promise的值都是成功的时候,最后结果才是成功的,且最后成功的结果值为数组中Promise成功的结果值组成的数组。
如下三个成功的Promise

 let p1=new Promise((resolve,reject)=>{
        resolve('OK')
    })
    let p2=Promise.resolve('success')
    let p3=Promise.resolve('11111')
    const result=Promise.all([p1,p2,p3])
    console.log(result)

在这里插入图片描述
如果有一个失败的promise对象,那么返回的结果也是失败的,且值为失败的对象的值:

let p1=new Promise((resolve,reject)=>{
        resolve('OK')
    })
    let p2=Promise.reject('error')
    let p3=Promise.resolve('11111')
    const result=Promise.all([p1,p2,p3])
    console.log(result)

在这里插入图片描述

4.race

传入的参数和all相同都是对象组成的数组,但是race返回的是第一个完成promise的结果的状态
使用上一个方法的代码:

   let p1=new Promise((resolve,reject)=>{
        resolve('OK')
    })
    let p2=Promise.reject('error')
    let p3=Promise.resolve('11111')
    const result=Promise.race([p1,p2,p3])
    console.log(result)

在这里插入图片描述

六、Promise相关问题

1.修改promise状态的三种方法

resolve:将状态pending修改成resolved
reject:将状态pending修改成rejected
thow抛出异常:将状态pending修改成rejected
(三者前提是初始状态为未决定的pending)

代码示例:

 var p=new Promise((resolve,reject)=>{
        // resolve("Success")
        // reject("Error")
        throw 'Error'
    })

2.一个promise可以指定多个成功/失败的回调函数,它都会调用吗

这里的指定其实就是then方法,答案是当promise改变为对应状态的时候会被调用
如下设置了两个then指定,最后结果渲染和打印都被执行了:

var p=new Promise((resolve,reject)=>{
        resolve("Success")
    })
    p.then((value)=>{
        console.log(value)
    })
    p.then((value)=>{
        document.body.innerHTML=value
    })

在这里插入图片描述

3.改变状态和指定回调函数的顺序

分两种情况。要看你的promise对象中执行的是同步还是异步函数。
(1)同步函数,改变状态先于指定回调函数
如下,对象内部是同步函数;
在这里插入图片描述
(2)异步函数,改变状态后于指定回调函数
定时器使用(看视频讲解也没明白为什么等了两秒后打印是异步的)应该就是同步代码会优先于异步代码执行。
视频地址(超多解释弹幕,脑袋大)

var p=new Promise((resolve,reject)=>{
        setTimeout(() => {
            resolve("Success")
        }, 2000);
    })
    p.then((value)=>{
        console.log(value)
    },()=>{
        
    })

4.then返回的结果状态由什么决定

由then指定的回调函数的结果决定
如下代码,如果p处对象的结果成功则由1处结果决定,否则由2处结果决定,

   //p
    var p=new Promise((resolve,reject)=>{
        resolve("Success")
    })
    var result=p.then((value)=>{
       //1
        console.log(value)
    },()=>{
       //2
    })
    console.log(result)

在这里插入图片描述
所以我们这里还可以在1或2处改变状态,代码分别如下
(1)then抛出异常

var p=new Promise((resolve,reject)=>{
        resolve("Success")
    })
    var result=p.then((value)=>{
        // console.log(value)
        //(1)抛出异常
        throw 'Error'
    },()=>{
    })

在这里插入图片描述
(2)返回的结果是非promise对象

   var p=new Promise((resolve,reject)=>{
        resolve("Success")
    })
    var result=p.then((value)=>{
        //(2)返回的结果是非promise对象
        return 123
    },()=>{

    })

在这里插入图片描述
(3)返回的结果是promise对象

   var p=new Promise((resolve,reject)=>{
        resolve("Success")
    })
    var result=p.then((value)=>{
        return new Promise((resolve,reject)=>{
        resolve("Ok")
        })
        
    },()=>{

    })

在这里插入图片描述

5.promise如何串连多个操作任务

这里便涉及到了链式调用问题(解决回调地狱,开篇提过)
如下代码:

    let p=new Promise((resolve,reject)=>{
        setTimeout(() => {
            resolve('OK')
        }, 1000);
    })
    p.then(value=>{//1
        return new Promise((resolve,reject)=>{
            resolve("Sucess")
        })
    }).then((value)=>{//2
        console.log(value)
    }).then((value)=>{//3
        console.log(value)
    })

这里的输出结果:
在这里插入图片描述

这里then是在先指定回调,而非执行回调,这里的执行要在状态改变之后才回去执行
所以这里,第一个then其返回的是内部新定义的promise对象,而第二个then它指定的是挂载他的内部状态改变即resolve的使用后开始执行并返回改变后的状态。第三个then,因为调用它的对象没有返回值,所以他此时的状态没有获得,所以是undefined

6.promise异常穿透

如下代码,猜测输出结果:

    const p=new Promise((resolve,reject)=>{
        reject('Error')
    })

    p.then((value)=>{
        console.log(111)
    }).then((value)=>{
        console.log(222)
    }).then((value)=>{
        console.log(333)
    }).catch((value)=>{
        console.log(value)
    })

最后会输出"Error",因为promise对象最后的结果是失败的,所以也不会去执行then而直接执行catch。
如果在then中出现失败,也都不用理会,他会全部放到最后的catch中执行,如下列代码,想要执行then的前提是上面promise对象返回的结果必须是成功的:

 const p=new Promise((resolve,reject)=>{
        // reject('Error')
         resolve("qqq")
    })

    p.then((value)=>{
        // console.log(111)
        throw 'ERROR'
    }).then((value)=>{
        console.log(222)
    }).then((value)=>{
        console.log(333)
    }).catch((value)=>{
        console.log(value)
    })

在这里插入图片描述

7.中断promise链

在使用promise链式调用时,在中间中断,不再调用后面的回调函数。我们可以在回调函数中返回一个pending状态的promise对象,然后后面的then就不会再执行

    const p=new Promise((resolve,reject)=>{
         resolve("qqq")
    })

    p.then((value)=>{
        console.log(111)
        return new Promise(()=>{})
    }).then((value)=>{
        console.log(222)
    }).then((value)=>{
        console.log(333)
    }).catch((value)=>{
        console.log(value)
    })

停留在“111”上
在这里插入图片描述
(先记这里结束,下一篇就要学习Promises的自定义封装了)
努力努力,写完自定义封装,卷起来

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值