一文教你搞定 Promise

一文教你搞定 PromiseES6 入门第五章 Promise Promise 是什么 Promise 是 ES6 引入的异步编程的新解决方案 旧的是谁 旧的解决方案是纯回调函数 语法上 Promise 是一个构造函数 用来封装异步操作并可以获取其成功或失败的结果 用来封装异步操作并可以获取其成功或失败的结果 Promise 的特点

大家好,我是讯享网,很高兴认识大家。

ES6 入门第五章

Promise

Promise 是什么?

Promise 是 ES6 引入的异步编程的新解决方案(旧的是谁?旧的解决方案是纯回调函数)。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。

用来封装异步操作并可以获取其成功或失败的结果。

Promise的特点

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected

Promise 的状态改变

1)pending 变成 fulfilled

2)pending 变成 rejected

说明:只有这两种状态改变情况,且一个Promise对象只能改变一次状态

​ 无论变成成功还是失败,都会有一个结果数据

​ 成功的结果数据一般称为 value ,失败的结果数据一般称为 reason

Promise缺点

  1. 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
  2. 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
  3. 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

Promise 的基本流程

在这里插入图片描述
讯享网

Promise基本使用

步骤:

  1. 创建一个新的Promise对象
  2. 执行异步操作任务
  3. 1 如果成功了,调用resolve(value)
    2. 如果失败了,调用reject(reason)
//1. 创建一个新的Promise对象 const p = new Promise((resolve,reject) => { 
   //执行器函数 //2.执行异步操作任务 setTimeout(() => { 
    const time = Date.now() //如果当前时间是偶数就代表成功,否则代表失败 if(time % 2 == 0 ){ 
    //3.1如果成功了,调用resolve(value) resolve('成功的数据,time=' + time) } else { 
    //3.2如果失败了,调用reject(reason) reject('失败的数据,time=' + time) } },1000) }) p.then( value => { 
    //接收得到成功的value数据 onResolved console.log('成功的回调',value) }, reason => { 
    //接收得到失败的reason数据 onRejected console.log('失败的回调',reason) } ) 

讯享网

在这里插入图片描述
在这里插入图片描述

为什么要用 Promise?

  1. 指定回调函数的方式更加灵活(灵活指的是时间的问题)
    1) 旧的:必须在启动异步任务前指定
    2)Promise:启动异步任务 => 返回 Promise 对象 => 给 Promise 对象绑定回调函数(甚至可以在异步任务结束后指定多个)

例子:创建一个音频文件

讯享网//成功的回调函数 function successCallback(result){ 
    console.log("声音文件创建成功:" + result); } //失败的回调函数 function failureCallback(result){ 
    console.log("声音文件创建失败:" + error); } 

1)使用纯回调函数

//1. 使用纯回调函数 creatAudioFileAsync(audioSettings, successCallback, failureCallback) 

2)使用Promise

讯享网const promise = createAudioFileAsync(audioSettings); setTimeout(()=> { 
    promise.then(successCallback, failureCallback); },3000) 
  1. 支持链式调用,可以解决回调地狱问题
  2. 什么是回调地狱?

    回调函数嵌套调用(多个串联的异步操作:第一个执行完,再执行第二个……),外部回调函数异步执行的 结果是嵌套的回调执行的条件

    //回调地狱 doSomething(function(result){ 
          doSomethingElse(result,function(newResult){ 
          doThirdThing(newResult,function(finalResult){ 
          console.log('Got the final result:' + finalResult) },failureCallback) },failureCallback) },failureCallback) 
  3. 回调地狱的缺点?

    不便于阅读

    不便于异常处理

  4. 解决方案

    Promise链式调用

    讯享网//使用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) 
  5. 终极解决方案

    async/await

    // async/await:回调地狱的终极解决方案 async function request() { 
          try{ 
          const result = await doSomething() const newResult = await doSomethingElse(result) const finalResult = await doThirdThing(newResult) console.log('Got the final result:' + finalResult) } catch(error) { 
          failureCallback(error) } } 

如何使用 Promise

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

    1)excutor 函数:执行器 (resolve,reject) => {}

    2)resolve 函数:内部定义成功时,我们调用的函数 value => {}

    3)reject函数:内部定义失败时,我们调用的函数 reason => {}

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

原型方法

​ 1)Promise.prototype.then 方法

​ 2)Promise.prototype.catch 方法

​ 3)Promise.prototype.finally 方法

自身的方法

all()、race()、reject()、resolve()、try()

  1. Promise.prototype.then 方法 (onResolved, onRejected) => {}

    ​ onResolved函数:成功的回调函数 (value) => {}

    ​ onRejected函数:失败的回调函数 (reason) => {}

    ​ 说明:指定用于得到成功value 的成功回调和用于得到失败reason的失败回调

    ​ 返回一个新的Promise对象

    讯享网new Promise((resolve, reject) => { 
          setTimeout(() => { 
          resolve("成功的数据") //reject("失败的数据") },1000) }).then( value => { 
          console.log('onResolved()1',value) } ).catch( reason => { 
          console.log('onRejected()1',reason) } ) 

在这里插入图片描述
3. Promise.prototype.catch 方法 (onRejected)=> {}

​ onRejected函数:失败的回调函数 (reason) => {}

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

new Promise((resolve, reject) => { 
    setTimeout(() => { 
    //resolve("成功的数据") reject("失败的数据") },1000) }).then( value => { 
    console.log('onResolved()1',value) } ).catch( reason => { 
    console.log('onRejected()1',reason) } ) 

在这里插入图片描述
4. Promise.prototype.finally 方法

用于指定不管 Promise 对象最后状态如何,都会执行的操作。

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

​ value:成功的数据或Promise对象

​ 作用:将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去 。

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

讯享网//产生;一个成功值为1的promise对象 const p1 = new Promise((resolve,reject) => { 
    resolve(1) }) //语法糖:就是简介语法 const p2 = Promise.resolve(2) console.log(p1) console.log(p2) 

在这里插入图片描述
6. Promise.reject 方法:(reason) => {}

reason:失败的原因

​ 作用:将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

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

//产生;一个失败值为3的promise对象 const p3 = new Promise((resolve,reject) => { 
    reject(3) }) const p4 = Promise.reject(3) console.log('p3:',p3) console.log('p4:',p4) 

在这里插入图片描述

讯享网//产生;一个成功值为1的promise对象 const p1 = new Promise((resolve,reject) => { 
    resolve(1) }) //语法糖:就是简介语法 const p2 = Promise.resolve(2) console.log('p1:',p1) console.log('p2:',p2) const p3 = new Promise((resolve,reject) => { 
    reject(3) }) const p4 = Promise.reject(3) console.log('p3:',p3) console.log('p4:',p4) p1.then(value => { 
   console.log(value)}) p2.then(value => { 
   console.log(value)}) p3.then(null,reason => { 
   console.log(reason)}) p4.catch(reason => { 
   console.log(reason)}) 

在这里插入图片描述
7. Promise.all 方法:(promises) => {}

promises:包含n个promise的数组

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

const p = Promise.all([p1, p2, p3]); 

上面代码中,Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。

p的状态由p1p2p3决定,分成两种情况。

(1)只有p1p2p3的状态都变成fulfilledp的状态才会变成fulfilled,此时p1p2p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1p2p3之中有一个被rejectedp的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

讯享网const p1 = new Promise((resolve,reject) => { 
    resolve(1) }) const p2 = Promise.resolve(2) const p3 = Promise.reject(3) const pAll = Promise.all([p1,p2]) console.log('pAll:',pAll) pAll.then( value => { 
    console.log('all onResolved()',value) }, reason => { 
    console.log('all onRejected()',reason) } ) 

在这里插入图片描述

const p1 = new Promise((resolve,reject) => { 
    resolve(1) }) const p2 = Promise.resolve(2) const p3 = Promise.reject(3) //const pAll = Promise.all([p1,p2]) const pAll = Promise.all([p1,p2,p3]) console.log('pAll:',pAll) pAll.then( value => { 
    console.log('all onResolved()',value) }, reason => { 
    console.log('all onRejected()',reason) } ) 

在这里插入图片描述
8. Promise.race 方法 (promises) => {}

promises:包含n个promise的数组

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

讯享网const p = Promise.race([p1, p2, p3]); 

上面代码中,只要p1p2p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

const p1 = new Promise((resolve,reject) => { 
    resolve(1) }) const p2 = Promise.resolve(2) const p3 = Promise.reject(3) const pRace = Promise.race([p1,p2,p3]) console.log('pRace',pRace) pRace.then( value => { 
    console.log('race onResolved()',value) }, reason => { 
    console.log('race onRejected()',reason) } ) 

在这里插入图片描述

讯享网const p1 = new Promise((resolve,reject) => { 
    resolve(1) }) const p2 = Promise.resolve(2) const p3 = Promise.reject(3) //const pRace = Promise.race([p1,p2,p3]) const pRace = Promise.race([p3,p1,p2]) console.log('pRace',pRace) pRace.then( value => { 
    console.log('race onResolved()',value) }, reason => { 
    console.log('race onRejected()',reason) } ) 

在这里插入图片描述
状态也不一定是由第一个决定,要看谁先完成,状态就为谁的状态

const p1 = new Promise((resolve,reject) => { 
    setTimeout(() => { 
    resolve(1) },100) }) const p2 = Promise.resolve(2) const p3 = Promise.reject(3) const pRace = Promise.race([p1,p2,p3]) console.log('pRace',pRace) pRace.then( value => { 
    console.log('race onResolved()',value) }, reason => { 
    console.log('race onRejected()',reason) } ) 

在这里插入图片描述

Promise的几大关键问题
  1. 如何改变Promise的状态?

    (1)resolve(value):如果当前是 pending 就会变成 fulfilled

    (2)reject(reason):如果当前是 pending 就会变成 rejected

    (3)抛出异常:如果当前是 pending 就会变成 rejected

    讯享网const p = new Promise((resolve,reject) => { 
          //resolve(1) //Promise变成 fulfilled 成功状态 //reject(2) //Promise变成 rejected 失败状态 //throw new Error('出错了') //抛出异常,promise变为rejected失败状态,reason为 抛出的error throw 3 //抛出异常,promise变为rejected失败状态,reason为 抛出的3 }) p.then( value => { 
         }, reason => { 
         console.log('reason',reason)} ) 

在这里插入图片描述
一个 Promise 指定多个成功/失败回调函数,都会调用吗?

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

const p = new Promise((resolve,reject) => { 
    //resolve(1) //Promise变成 fulfilled 成功状态 //reject(2) //Promise变成 rejected 失败状态 //throw new Error('出错了') //抛出异常,promise变为rejected失败状态,reason为 抛出的error throw 3 //抛出异常,promise变为rejected失败状态,reason为 抛出的3 }) p.then( value => { 
   }, reason => { 
   console.log('reason',reason)} ) p.then( value => { 
   }, reason => { 
   console.log('reason2',reason)} ) 

在这里插入图片描述

  1. 改变 Promise 状态和指定回调函数谁先谁后?

    (1)都有可能,正常情况下是先指定回调再改变状态,但也可以先改状态再指定回调

    (2)如何先改状态再指定回调?

    ​ 1)在执行器中直接调用 resolve()/reject()

    ​ 2)延迟更长时间才调用 then()

    (3)什么时候才能得到数据?

    ​ 1)如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据

    ​ 2)如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据

    讯享网//常规:先指定回调函数,后改变的状态 new Promise((resolve,reject) => { 
          setTimeout(() => { 
          resolve(1) //后改变的状态(同时指定数据),异步执行回调函数 },1000) }).then(//先指定回调函数,保存当前指定的回调函数 value => { 
         console.log('value',value)}, reason => { 
         console.log('reason',reason)} ) /*++++++++++++++++++++++++*/ //如何先改状态,后指定回调函数 new Promise((resolve,reject) => { 
          resolve(1) //先改变的状态(同时指定数据) }).then(//后指定回调函数,异步执行回调函数 value => { 
         console.log('value2',value)}, reason => { 
         console.log('reason2',reason)} ) /*++++++++++++++++++++++++*/ const p = new Promise((resolve,reject) => { 
          setTimeout(() => { 
          resolve(1) //先改变的状态(同时指定数据),异步执行回调函数 },1000) }) setTimeout(() => { 
          p.then( value => { 
         console.log('value3',value)}, reason => { 
         console.log('reason3',reason)} ) },1100) 
  2. 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) }, reason => { 
          console.log('onRejected1()',reason) }).then( value => { 
          console.log('onResolved2()',value) }, reason => { 
          console.log('onRejected2()',reason) } ) 

在这里插入图片描述

讯享网new Promise((resolve,reject) =>{ 
    resolve(1) //reject(1) }).then( value => { 
    console.log('onResolved1()',value) // return 2 // return Promise.resolve(3) return Promise.reject(5) }, reason => { 
    console.log('onRejected1()',reason) }).then( value => { 
    console.log('onResolved2()',value) }, reason => { 
    console.log('onRejected2()',reason) } ) 

在这里插入图片描述
5. Promise如何串连多个操作任务?

(1)Promise 的then()返回一个新的 Promise,可以开成then()的链式调用

(2)通过then的链式调用串连多个同步/异步任务

new Promise((resolve,reject) =>{ 
    setTimeout(() => { 
    console.log("执行任务1(异步)") resolve(1) },1000) }).then( value => { 
    console.log('任务1的结果:',value) console.log('执行任务2(同步)') return 2 } ).then( value => { 
    console.log('任务2的结果:',value) return new Promise((resolve,reject) => { 
    //启动异步任务3(异步) setTimeout(() => { 
    console.log('执行任务3(异步)') resolve(3) },1000) }) } ).then( value => { 
    console.log('任务3的结果:',value) } ) 

在这里插入图片描述
Promise异常传/穿透?

(1)当使用Promise的then链式调用时,可以在最后指定失败的回调

(2)前面任何操作出了异常,都会传到最后失败的回调中处理

讯享网new Promise((resolve,reject) =>{ 
    //resolve(1) reject(1) }).then( value => { 
    console.log('onResolved1()',value) return 2 }, //reason => {throw reason} ).then( value => { 
    console.log('onResolved2()',value) return 3 }, //reason => {throw reason} ).then( value => { 
    console.log('onResolved3()',value) }, reason => Promise.reject(reason) ).catch(reason => { 
    console.log('onRejected1()',reason) }) 

执行reject(1)这个函数,因为第一个then()里面没有reason函数,其实默认为reason => {throw reason},所以会一直往下,然后到第二个then(),第二个也没有reason函数,所有到第三个then(),第三个也没有,所有到最后的catch,这就是传/穿透。
在这里插入图片描述
6. 中断Promise链?

(1)当使用Promise的then链式调用时,在中间中断,不再调用后面的回调函数

(2)办法:在回调函数中返回一个pending状态的Promise对象

new Promise((resolve,reject) =>{ 
    //resolve(1) reject(1) }).then( value => { 
    console.log('onResolved1()',value) return 2 }, //reason => {throw reason} ).then( value => { 
    console.log('onResolved2()',value) return 3 }, reason => { 
   throw reason} ).then( value => { 
    console.log('onResolved3()',value) }, reason => Promise.reject(reason) ).catch(reason => { 
    console.log('onRejected1()',reason) //throw reason //return Promise.reject(reason) return new Promise(() => { 
   })//返回一个pending的Promise 中断Promise链 }).then( value => { 
    console.log('onResolved3()',value) }, reason => { 
    console.log('onRejected2()',reason) } ) 

在这里插入图片描述
如果不想执行catch后面的then了,则用 return new Promise(() => {})中断Promise链,因为此时的状态为pending,既不是fulfilled状态也不是rejected。

async 与 await

async 函数

  1. 函数的返回值为Promise对象
  2. Promise对象的结果由async函数执行的返回值决定
讯享网// async 函数的返回值是一个Promise对象 async function fn1() { 
    return 1 } const result = fn1() console.log(result) 

在这里插入图片描述
await 表达式

  1. await 右侧的表达式一般为 Promise对象,但也可以是其它的值
  2. 如果表达式是Promise对象,await返回的是Promise成功的值
  3. 如果表达式是其它值,直接将此值作为await的返回值
function fn2() { 
    return new Promise((resolve,reject) => { 
    setTimeout(() => { 
    resolve(5) },1000) }) } async function fn3() { 
    const value = await fn2() //await右侧表达式为Promise,得到的结果就是Promise成功的value console.log('value',value) } fn3() 

在这里插入图片描述

讯享网function fn5() { 
    return 9 } async function fn3() { 
    //const value = await fn2() //await右侧表达式为Promise,得到的结果就是Promise成功的value const value = await fn5() //await右侧表达式不是Promise,得到的结果就是它本身 console.log('value',value) } fn3() 

在这里插入图片描述
注意:

  1. await必须写在async函数中,但async函数中可以没有await
  2. 如果await的Promise失败了,就会抛出异常,需要通过try…catch来捕获处理
function fn2() { 
    return new Promise((resolve,reject) => { 
    setTimeout(() => { 
    //resolve(5) reject(6) },1000) }) } async function fn3() { 
    try{ 
    const value = await fn2() console.log('value',value) } catch (error) { 
    console.log('得到失败的结果',error) } } fn3() 

在这里插入图片描述

小讯
上一篇 2025-02-22 19:07
下一篇 2025-02-13 15:55

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/40157.html