promise的理解和使用-尚硅谷教程笔记

    科技2022-07-15  123

    一,理解

    抽象表达:promise是js中进行异步编程的新的解决方案。(旧的是纯粹的回调函数) 具体表达:从语法上来看,promise是一个构造函数。从功能上来说,promise对象用来封装一个异步操作,并可以获取其结果。

    异步操作的第一阶段处理方式:回调函数作为参数传入,异步结果作为回调函数的参数传入,回调函数在异步操作后调用,以完成对异步结果的获取和处理。

    之前就学习过,异步操作的执行,是无法直接得到执行结果的。 为了拿到结果,人们将函数作为参数来定义异步操作的函数: 类似于上图这样,利用回调函数作为异步操作的参数传入,在异步操作的函数内部调用回调函数,从而取得异步结果(作为回调函数的参数),并做相应的处理。 也就是说,对异步操作的结果处理放在回调函数中了。 但是,若是出现多层回调函数嵌套的情况,就会产生回调地狱。为了解决回调地狱的问题,人们引入了promise。 所以说它是js中进行异步编程的新的解决方案。

    异步操作的第二阶段处理方式:promise

    回调地狱的产生,原因还是回调函数对结果的处理和异步操作终究还是在一起,并没有把分离。而引入promise的最大作用,就是把异步操作的过程和结果做到了分离,可以用promise.then()来获取和处理异步操作的结果。

    异步操作的第三阶段处理方式:异步函数

    promise还是有些繁琐,于是es7又推出了async和await,将同步操作以同步的方式书写出来。

    二,promise的状态改变

    Promise对象只有三种状态。

    异步操作“未完成”(pending) 异步操作“已完成”(resolved,又称fulfilled) 异步操作“失败”(rejected)

    这三种的状态的变化途径只有两种且不可逆,且一个promise只能改变以此一次状态。

    异步操作从“未完成”到“已完成” 异步操作从“未完成”到“失败”。

    因此,Promise对象的最终结果只有两种。要么成功,要么失败。于是只会有一种数据产生,成功的结果数据称value,失败的结果数据称reason

    异步操作成功,Promise对象传回一个值,状态变为 resolved。 异步操作失败,Promise对象抛出一个错误,状态变为 rejected。

    三,promise的基本运行流程

    四,promise的基本使用

    const p= new Promise((resolve,reject)=>{ //这个回调函数,又被称之为执行器函数,异步操作放在这里面执行,参数是两个函数(内部定义好了的) //执行异步操作 setTimeout(()=>{ const time=Date.now() //如果当前时间是偶数就代表成功 //如果成功了,就执行resolve(value),value时成功数据,作为resolve函数的参数 if(time % 2 ==0){ resolve('成功啦') }else{ //如果异步操作失败了,调用reject(reason),reason是作为它的参数 reject('失败惹') } },1000) }) //对异步操作结果的处理 p.then( value=>{ //接收到成功的value数据 onResolved console.log('成功的话就会执行这里的函数---',value) }, reason=>{ //接收到失败的reason数据 onRejected console.log('失败的话就会执行这里的函数---',reason) } )

    五,为什么要使用promise

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

    旧的纯粹回调函数的形式,必须在启动异步任务前,就指定好回调函数(作为异步操作函数的形参)。而promise,则是启动异步任务,返回promise对象,然后再给promise对象绑定回调函数(甚至可以在异步任务完成后绑定) 例如:使用纯粹的回调函数:

    //成功的回调函数 function successCallback(result){ //对result的一系列操作,例如下面这行打印结果 console.log(result) } //失败的回调函数 function failureCallback(error){ //对error的一系列操作 console.log(error) } //定义异步操作的函数 function createAudioFileAsync(audioSettings,successFun,errorFun){ //针对audioSettings中的一些参数,进行异步操作 //……一系列的异步操作代码,得成功的话,得到result,失败的话得到error if(成功){ // 执行成功的操作,并将结果传入作为参数 successFun(result) }else(失败){ // 执行失败后的操作,并将结果传入作为参数 errorFun(error) } } //1.使用纯粹的回调函数 //使用并进行异步操作,直接指定回调函数,作为异步操作函数的实参传入,使得异步操作的结果也在这个异步操作的函数中处理 createAudioFileAsync(audioSettings,successCallback,failureCallback) // 2. 使用promise //直接开始异步操作,只是没有在第一时间完成 const promise = createAudioFileAsync(audioSettings) //在后面指定的回调函数,异步操作和异步操作的结果做到了分离。 promise.then(successCallback,failureCallback)

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

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

    // 1. 回调地狱 doSomething(function(result){ doSomethingElse(result, function(newResult){ doThirdThing(newResult, function(finalResult){ console.log('Got the final result:' + finalResult) }, failureCallback) }, failureCallback) }, failureCallback) // 2. 使用promise的链式调用解决回调地狱 doSomething().then(function(result){ return doSomethingElse(result) }) .then(function(newResult) { return doThirdThing(newResult) }) .then(function(finalResult){ console.log('Got the final result:'+finalResult) }) .catch(failureCallback) // 3. async/await:回调地狱的终极解决方案 async function request() { try { const result=await doSomething() const newResult=await doSomethingElse(result) const finalResult=await soThirdThing(newResult) console.log('Got the final result'+finalResult) } catch(error) { failureCallback(error) } }

    六,promise的API使用

    1、Promise构造函数:Promise(excutor){}

    excutor函数:同步执行 (resolve, reject)=>{} resolve函数:内部定义成功时我们调用的函数 value=>{} reject函数:内部定义失败时我们调用的函数 reason=>{} 说明:excutor会在Promise内部立即同步回调,异步操作在执行器中执行

    2、Promise.prototype.then方法:(onResolved, onRejected)=>{}

    onResolved函数:成功的回调函数 (value)=>{} onRejected函数:失败的回调函数 (reason)=>{} 说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,返回一个新的promise对象

    3、Promise.prototype.catch方法:(onRejected)=>{}

    onRejected函数:失败的回调函数 (reason)=>{} 说明:then()的语法糖,相当于:then(undefined, onRejected)

    new Promise((resolve, reject)=>{ //一系列异步操作,得到结果result,成功则调用resolve,失败则调用reject resolve(result) // reject(result) }).then( //对成功的结果的处理,参数是一个函数,此函数的参数value就是result, value=>{ //函数的内容里面写对异步结果的处理 console.log('onResolved()', value) } ).catch( //对失败的结果的处理,参数是一个函数,此函数的参数reason就是result, reason=>{ console.log('onRejected()', reason) } )

    4、Promise.resolve方法:(value)=>{}

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

    5、Promise.reject方法:(reason)=>{}

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

    // 产生一个成功值为1的promise对象 const p1=new Promise((resolve, reject)=>{ resolve(1) }) // 产生一个成功值为2的promise对象 const p2=Promise.resolve(2) // 语法糖 const p3=Promise.reject(3) p1.then(value=>{console.log(value)}) //1 p2.then(value=>{console.log(value)}) //2 p3.catch(reason=>{console.log(reason)}) //3

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

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

    // 产生一个成功值为1的promise对象 const p1=new Promise((resolve, reject)=>{ resolve(1) }) // 产生一个成功值为2的promise对象 const p2=Promise.resolve(2) // 语法糖 const p3=Promise.reject(3) // 一个失败的话返回失败的数据,成功的话返回成功的数组 const pAll = Promise.all([p1,p2,p3]) pAll.then( values=>{ //此时的valuse是一个数组,每一项对应是每个promise的结果【1,2,3】 }, reason=>{ console.log('all onRejected()', reason) // 3 } )

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

    promises: 包含n个promise数组 说明:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态

    const pRace = Promise.race([p1,p2,p3]) //不知道谁先完成,一旦有人成功,则取它,其他人不要了 pRace.then( value=>{ console.log('race onResolved()', value) }, reason=>{ console.log('race onRejected()', reason) } )

    七,promise的几个关键问题

    1,如何改变promise 的状态

    resolve:如果当前是pendding就会变为resolved reject:如果当前是pendding就会变为rejected 抛出异常:如果当前是pendding就会变为rejected

    const p= new Promise((resolve,reject)=>{ //resolve(1) promise变为resolved成功状态 //reject(2) promise变为rejected失败状态 //throw new Error('出错了') 抛出异常,promise变为rejected失败异常,reason为抛出的异常 throw 3 //抛出异常,promise变为rejected失败状态,reason为抛出的3 }) p.then( value=>{} reason =>{console.log(reason)} ) p.then( value=>{} reason =>{console.log('第二次'+reason)} ) //两次都可以执行,也就是说,可以对异步操作的结果做不同的处理

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

    先指定回调函数,然后才改变状态: 先改变状态,后指定回调函数: 或者,直接比异步操作结束时间还晚,来指定回调函数:

    3,promise的回调函数,都是异步执行的

    看这段代码,resolve(1)是同步执行的,.then()也是同步执行的,这时候,状态已经改变,回调函数也指定好了,那么它是同步执行的吗?不,它是异步执行的,可以由------先输出从而判断出来。

    4,promise.then()返回的新promise的结果状态是由什么决定的?

    (1),简单表达:由then()指定的回掉函数的执行结果决定 (2),详细表达:

    1,如果抛出异常,新promise变为rejected状态,reason为抛出的异常 2,如果返回的是非promise的任意值,新promise变为resolved,value为返回的值。 3,如果返回的是另一个新的promise,此promise的结果就会变成新promise的结果 new Promise((resolve,reject)=>{ resolve(1) }).then( value=>{ console.log('onResolved1()',value) //return 2 //return Promise.resolve(3) //return Promise.reject(4) throw 5 }, reason=>{ console.log('onRejected1()',reason) } ).then( value=>{ console.log('onResolved2()',value) }, reason=>{ console.log('onRejected2()',reason) } ) //r啥也不return时,返回结果是:onResolved1() 1 onResolved2() underfined ,因为没有指定value的值 //return 2时,即为返回非promise的任意值,新promise变为resolved,value为返回的值2。于是结果onResolved1() 1 onResolved2() 2 //return Promise.resolve(3)时,返回的是另一个新的promise,此promise的结果就会变成新promise的结果3 //于是返回的结果是:onResolved1() 1 onResolved2() 3 //return Promise.reject(4)和上一个一样,返回的最终结果:onResolved1() 1 onRejected2() 4 //throw 5,如果抛出异常,新promise变为rejected状态,reason为抛出的异常 //最终的结果:onResolved1() 1 onRejected2() 5

    由此可以知道,链式写promise中,第一个异步操作的promise失败 了并不会导致后续的promise失败,后续的promise的失败与否还是由新promise决定的。

    5,promise的异常传透

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

    6,中断promise链

    1,当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数。 2,办法:在回调函数中返回一个pendding状态的promise对象

    原理就是返回的新promise没有结果,所以就不会继续调用reject或者resolve,所以就中断了这个链……

    Processed: 0.009, SQL: 8