promise

文章目录

      • Promise基本使用
      • 对比不同回调方式
      • promise API
      • promise的几个关键问题
        • 如何改变promise的状态?
        • 改变promise状态 和 指定回调函数 谁先谁后
        • promise.then()返回的新promise的结果状态由什么决定 (重点)
      • asyn和await
      • 宏队列和微队列

Promise是JS中进行异步编程的新的解决方案 (旧的是纯回调)

  • 语法上: Promise是一个构造函数
  • 功能上: Promise对象用来封装一个异步操作并可以获得其结果

Promise状态
pending变为resolved;pending变为rejected
说明:

  • 只有这两种状态,且一个promise对象只能改变一次
  • 无论变为成功还是失败,都会有一个结果数据
  • 成功的结果数据一般称为value,失败的结果数据一般称为reason
  • 成功:resolved 失败:rejected

在这里插入图片描述

new Promise( function(resolve, reject) {…} /* executor */ );

executor是带有 resolve 和 reject 两个参数的函数 。 Promise构造函数执行时立即调用executor 函数,
resolve 和 reject 两个函数作为参数传递给executor(executor
函数在Promise构造函数返回所建promise实例对象前被调用)。 resolve 和 reject
函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。executor
内部通常会执行一些异步操作,一旦异步操作执行完毕(可能成功/失败),要么调用resolve函数来将promise状态改成fulfilled,要么调用reject
函数将promise的状态改为rejected。如果在executor函数中抛出一个错误,那么该promise
状态为rejected。executor函数的返回值被忽略。

Promise基本使用

//1.创建一个新的promise对象--传入的参数是一个回调函数,也就是定义中所说的执行器函数
//尽量使用const变量
const p = new Promise((resolve, reject) => {
      //执行器函数是同步回调!!!
  console.log('执行 excutor') //是会立刻执行的
  //2.执行异步操作
  setTimeout(() => {
       
    const time = Date.now()//如果当前时间是偶数就代表成功,否则代表失败
    //3.1 如果成功了,调用resolve(value)
    if( time % 2 === 0 ){
     
      resolve('成功的数据,time=' + time)
    } else {
     
    //3.2 如果失败,调用reject(reason)
      reject('失败的数据,time=' + time)
    }
  }, 1000)
})
console.log('new Promise()之后')  //先输出执行 excutor

// then()指定成功或失败的回调函数
p.then(
  value => {
      //接收得到成功的value数据  onResolved: 当变为resolved时执行
    console.log('成功的回调', value)
  },
  reason => {
      //接收失败得到的reason  onRejected
    console.log('失败的回调', reason)
  }
)

执行 excutor
new Promise()之后
失败的回调 失败的数据,time=1586181072611 //promise定义时,reject(reason)

对比不同回调方式

  1. 指定回调方式更加灵活
  • 旧的: 必须在启动异步任务前指定
  • promise:启动异步任务=>返回promise对象 =>给promise对象绑定回调函数(甚至可以在异步任务结束之后指定)
    异步任务可以先进行,我可以3s之后再来取结果,也就是我需要的时候去拿
  1. 支持链式调用, 解决回调地狱
  • 回调地狱:回调函数嵌套套用,外部回调函数异步执行的结果是嵌套的回调函数执行的条件
    缺点:不便于阅读/不便于异常处理
    解决方案:promise链式调用
    终极解决:async/await
//伪代码
function successCallback(result) {
     
  console.log('声音文件创建成功' + result)
}

function failureCallback(error) {
     
  console.log('声音文件创建失败' + error)
}

/* 1.1 纯回调函数 */
//启动任务(audioSettings)前必须指定回调函数(callback)
createAudioFileAsync(audioSettings, successCallback, failureCallback)

/* 1.2 promise */
//可在启动任务(audioSettings)后指定回调函数(callback)
const promise = createAudioFileAsync(audioSettings)
setTimeout(() => {
     
  promise.then(successCallback, failureCallback)
}, 1000)

/* 2.1 回调地狱 */
//回调函数的嵌套
doSomething1(function (result) {
      //参数一:function(result)就是sucessCallback,接收成功的结果result
  doSomethingElse2(result, function (newResult) {
     
    doThirdThing3(newResult, function (finalResult) {
     
      console.log('Got the final result' + finalResult)
    }, failureCallback)
  }, failureCallback)
}, failureCallback)


/* 2.2 promise链式调用 */
doSomething().then(function(result) {
      //result是doSomething函数成功执行的返回值
  return doSomethingElse(result)      //执行器函数,同步回调
})
.then(function(newResult){
       //newResult是doSomethingElse成功执行的返回值
  return doThirdThing(newResult)
})
.then(function(finalResult){
     
  console.log('Got the final result' + finalResult)
})
.catch(failureCallback) //统一的错误处理,上面无论哪个promise出了问题,都会到这里:异常传透


/* 2.3 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 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. Prmise.prototype.catch方法:(onRejected)=>{}
    onRejected函数:失败的回调函数 (reason)=>{}
    说明:then()的语法糖,相当于then(undefined, onRejected)

快速创建promise对象

  1. Promise.resolve方法:(value)={}
    value:成功的数据或promise对象
    说明:返回一个成功/失败的promise对象

  2. Promise.reject方法:(reason)=>{}
    reason:失败的原因
    说明:返回一个失败的promise对象

  3. Promise.all方法: (promises) => {}
    promises: 包含n个promise的数组
    说明: 返回一个新的promise, 只有所有的promise都成功才成功,只要有一个失败了就直接失败

  4. Promise.race方法: (promises) => {}
    promises: 包含n个promise的数组
    说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态

new Promise((resolve, reject) => {
     
  setTimeout( () => {
     
    resolve('成功') //resolve就像是一个传递数据的运输机
    // reject('失败') 指定了也没有,promise状态只能改变一次
  }, 1000 )
})
.then( 
  value => {
     
    console.log('onResolved()1', value)
  }
)
.catch(
  reason => {
     
    console.log('onRejected()1', reason) //如果上面指定了reject('失败'),就走到这里
  }
)


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

//const pAll = Promise.all([p1,p2,p3]) 三个异步请求
const pAll = Promise.all([p1,p2])//完全跟在这个数组里的顺序有关,跟异步完成的顺序无关
pAll.then(
  values => {
     
    console.log('all onResolved()', values)
  },
  reason => {
     
    console.log('all onRejected()', reason)
  }
)

// Promise.race: 看谁先完成(比赛)
const pRace = Promise.race([p1,p2,p3])
pRace.then(
  value => {
     
    console.log('race onResolved()', value)
  },
  reason => {
     
    console.log('race onResolved()', reason)
  }
)

promise的几个关键问题

如何改变promise的状态?

(1)resolve(value):如果当前是pending,就会变成resolved
(2)reject(reason):如果当前是pending,就会会变成rejected
(3)抛出异常:如果当前是pending,就会会变成rejected

const p =new Promise((resolve, reject)=>{
     
  // resolve(1) promise变为resolved成功状态
  // 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)}
)


error属于promise哪个状态
// const p = new Promise((resolve, reject)=>{
     
//   throw new Error('出错了') //属于reject状态
// })

// p.then(
//   value => {},
//   reason => { console.log('reason', reason) } //reason Error: 出错了
// )


一个promise指定多个成功/失败回调函数,都会调用吗?
当promise改变为对应状态时,都会调用


const p2 = new Promise((resolve, reject)=>{
     
  throw new Error('出错了') //属于reject状态
})

p2.then(
  value => {
     },
  reason1 => {
      console.log('reason1', reason1) } //reason1 Error: 出错了
).then(
  reason2 => {
      console.log('reason2', reason2) }  //reason2 undefined
)

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

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

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

  • 在执行器中直接调用resolve()/reject()
  • 延迟更长时间才调用then()

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

  • 如果先指定回调,那当状态发生改变时,回调函数就会调用,得到数据
  • 如果先改变状态,那么当指定回调时,回调函数就会调用,得到数据
/* 3.状态改变与指定回调函数的先后次序 */
new Promise((resolve, reject)=>{
     
  setTimeout(()=>{
     
    resolve(1)  //后改变状态(同时指定数据),异步执行 回调函数
  },1000) //有定时器
}).then(  //先指定回调函数, 所以保存 当前指定的回调函数
  value => {
     },
  reason => {
      console.log('reason', reason) }
)

new Promise((resolve, reject)=>{
     
    resolve(1)  //先改变状态(同时指定数据)
}).then(  //后指定回调函数,异步执行 回调函数
  value => {
      console.log('value', value) },
  reason => {
      console.log('reason', reason) }
)
console.log('-----')  //先输出----, 再输出value 1

promise.then()返回的新promise的结果状态由什么决定 (重点)

由then()指定的回调函数 执行的结果 决定
  • 如果抛出异常,新promise变为rejected,reason为抛出的异常
  • 如果返回的是非promise的任意值(上一个promise是resolve还是reject都没关系),新promise变为resolved,value为返回的值
  • 如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
new Promise((resolve, reject)=>{
     
  resolve(1)
}).then(
  value => {
     
    console.log("onResolved1()", value)//1 这个promise return undefined, 下个then得到的value就是undefined
  },
  reason => {
     console.log("onRejected1()", reason)//这个promise return undefined, 下个then得到的value就是undefined
})
.then(
  value => {
     
    console.log("onResolved2()", value)//undefined
  },
  reason => {
     
    console.log("onRejected2()", reason)
  }
)

//进一步
new Promise((resolve, reject)=>{
     
  resolve(1)
}).then(
  value => {
     
    console.log("onResolved1()", value)
    //return 2  //新Promise状态为resolved, return得到value值
    //return Promise.resolve(3) //返回一个新promise, Promise是函数对象
    throw 4   //新Promise状态为rejected, throw得到value值
  }
).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) => {
      //启动的异步任务要放在promise里
      //启动任务3(异步)
      setTimeout(() => {
     
        console.log('执行任务3(异步)')
        resolve(3)
      }, 1000)
    })
  }
).then(
  value => {
     
    console.log('任务3的结果', value)
  }
)
// 执行任务1(异步)
// 任务1的结果 1
// 执行任务2(同步)
// 任务2的结果 2
// 执行任务3(异步)
// 任务3的结果 3

/* 6. 异常传透 
  (1)当使用promise的then链式调用时,可以在最后指定失败的回调
  (2)前面任何操作出了异常,都会传到最后失败的回调中处理[一层一层传递]
*/
new Promise((resolve, reject) => {
     
  //resolve(1)
  reject(1)
}).then(
  value => {
     
    console.log('onResolved1()', value)
    return 2
  },
  // reason => throw reason 在这个then只写了成功的回调,相当于有这句话:默认failureCallback
  //reason => Promise.reject(reason) 

).then(
  value => {
     
    console.log('onResolved2()', value)
    return 3
  }
  // reason => throw reason 在这个then只写了成功的回调,相当于有这句话:默认failureCallback
).then(
  value => {
     
    console.log('onResolved3()', value)
  // reason => throw reason 在这个then只写了成功的回调,相当于有这句话:默认failureCallback
  }
).catch(reason => {
     
  console.log('onRejected1()', reason)
})



/* 7. 中断Promise链 
  (1)当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数
  (2)办法:在回调函数中返回一个pending状态的promise对象
*/
new Promise((resolve, reject) => {
     
  reject(1)
}).then(
  value => {
     
    console.log('onResolved1()', value)
    return 2
  }
).then(
  value => {
     
    console.log('onResolved2()', value)
    return 3
  }
).then(
  value => {
     
    console.log('onResolved3()', value)
  }
).catch(reason => {
     
  console.log('onRejected1()', reason)
  return new Promise(()=>{
     })  //返回一个pending的promise 中断promise链
}).then(
  value => {
      console.log('onResolved4()', value) },
  reason => {
      console.log('onRejected4()', reason)}
)

asyn和await

/*
  1.async function (function return Promise)
    函数返回Promise对象
    promise对象的结果由async函数执行的返回值决定
  
  2. await expression (value or Promise)
    expression一般是Promise对象,也可以是其他值
      如果是Promise对象,await返回的是Promise成功的值
      如果是其他值,直接将此值作为await的返回值

  3. 
    await必须写在async中,但async可以没有await
    如果await的Promise失败,就会抛出异常,需通过try...catch...捕获处理
*/


// async函数返回一个promise对象
async function fn1() {
     
  //return 1
  //throw 2
  //return Promise.resolve(3)
  return new Promise((resolve, reject)=>{
     
    setTimeout(()=>{
     
      resolve(4)
    }, 1000)
  })
}

const result = fn1()
//console.log(result) //Promise { 1 }

result.then(
  value => {
     
    console.log('onResolved()', value)
  },
  reason => {
     
    console.log('onRejected()', reason)
  }
)


/*------------------------*/

function fn2(){
     
  return new Promise((resolve, reject)=>{
     
    setTimeout(()=>{
     
      //resolve(4)
      reject(6)
    }, 1000)
  })
}

function fn4(){
     
  return 5
}

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

fn3()

async function fn5(){
     
  try{
     
    const value = await fn2()
    console.log('fn5 value', value)
  }catch(error){
       //捕获失败promise的结果
    console.log('fn5 error', error)
  }
}

fn5()

宏队列和微队列

/*
  宏队列:
    定时器回调
    ajax回调
    dom事件回调

  微队列:
    Promise回调
    mutation回调
*/

// setTimeout(()=>{  //立即放入宏队列
//   console.log('timeout callback1()')
//   Promise.resolve(3).then(
//     value => {  //立即放入微队列
//       console.log('Promise onResolved3()', value)
//     }
//   )
// },0)

// setTimeout(()=>{  //立即放入宏队列
//   console.log('timeout callback2()')
// },0)

// Promise.resolve(1).then(
//   value => {  //立即放入微队列
//     console.log('Promise onResolved1()', value)
//     setTimeout(()=>{
     
//       console.log('timeout callback3()', value)
//     },0)
//   }
// )

// Promise.resolve(2).then(
//   value => {  //立即放入微队列
//     console.log('Promise onResolved2()', value)
//   }
// )


//  先执行微队列
// Promise onResolved1() 1
// Promise onResolved2() 2
// timeout callback1()
// timeout callback2()
// timeout callback3() 1
// Promise onResolved3() 3


/* ----------------------- */
setTimeout(()=>{
     
  console.log(1)
},0)

new Promise((resolve, reject) => {
     
  console.log(2)
  resolve()
}).then(
  value => {
     
    console.log(3)
  }
).then(
  value => {
     
    console.log(4)
  }
)

console.log(5)

你可能感兴趣的:(前端)