ES6之Promise

简介

在常见的ajax请求中,如果异步请求函数之间存在依赖关系,函数之间就会产生嵌套,过多的嵌套会使得代码看起来十分臃肿并且可读性差、难以维护,这种现象俗称“回调地狱(callback hell)”。ES6标准出现之后,处理异步数据流又多了一种解决方案—构造函数Promise,它比传统的解决方案(回调函数)更加合理和更加强大 。
以下是嵌套多层ajax请求的伪代码:

// ajax请求的伪代码
function ajax(url, sucessCallback, failCallback) {
  // url:请求的url
  // sucessCallback:成功的回调函数
  // failCallback:失败的回调函数
}

ajax(url1, (res1) => {
  ajax(url2, (res2) => {
    ajax(url3, (res3) => {
      doSomething(res1, res2, res3)
    })
  })
})

构造函数

以下是Promise对象的构造函数:

let promise = new Promise(function(resolve, reject) {
  // executor
  resolve('123')			// 成功并返回'123'
});

在创建promise对象时,我们需要在构造函数中传入一个回调函数称为executor,该函数会立即执行,其参数resolve和reject是js提供的回调函数,用来改变promise的状态(pending、fulfilled、rejected),在执行这两个函数之前其状态为pending,当执行resolve(value)表示任务成功,promise的状态转变为fulfilled并返回结果value,执行reject(error)表示任务失败,promise的状态转变为rejected并返回结果error,这两个结果值在之后的链式调用.then方法中获取。需要注意的是,promise对象的状态一经改变便不会再变。
状态迁移如下图所示:

then方法

当promise对象创建后我们该如何获取它返回的成功或失败的值呢,promise提供了可以进行链式调用的then方法来获取,它提供了两个回调函数,分别用来处理成功和失败的返回值。
用法如下:

  // 处理结果
  promise.then((res) => {
    // 成功结果
    console.log(res)		// 123
    return '456'
  }).then((res) => {
    // 成功结果
    console.log(res)		// 456
    return Promise.reject('error')
  }).then(() => {}, (error) => {
    // 失败结果
    console.log(error)		// error
  })

这里需要注意,then方法接收到的值取决于上一个输出,有如下规则:

  1. 如果then方法中返回的还是一个promise对象则会将该对象继续向下传递到下一个then方法中处理
  2. 如果then方法返回的是一个普通值,则会将该值传递到下一个then方法的成功回调函数中
  3. 如果then方法返回一个失败的 Promise,或是抛出一个异常,则会走到下一层的失败的回调函数中去

promise基本用法

// 1. 基本用法
/* resolved 成功时的回调函数  rejected失败时的回调函数 */
let pro = new Promise(function(resolved, rejected) {
  let obj = {
    result: 200,
    data: {
      name: 'jack',
      age: 23
    },
    error: '出错了'
  }
  if(obj.result === 200) {
    resolved(obj.data)
  } else {
    rejected(obj.error)
  }
})


/* 接收回调函数传来的值 */
pro.then((result) => {
  console.log(result)
}, (err) => {
  console.log(err)
})


// pro.catch(err=>{}) 相当于pro.then(null, err=>{})
pro.catch(err => {
  console.log(err)
}) 

Promise.resolve()

创建一个promise对象并且该对象的状态为fulfilled
Promise.resolve()相当于new Promise(resolve => resolve())

Promise.reject()

创建一个promise对象并且该对象的状态为rejected
Promise.reject()相当于new Promise((resolve, reject) => reject())

Promise.all()

Promise.all方法提供了并行执行异步操作的功能,接收一个promise对象的数组,当所有异步操作执行完成后才返回结果,并且全部成功才会返回成功结果,如果有一个失败了就会返回失败,返回值也是一个数组,顺序和传入的相同,利用该方法我们可以同时从不同的URL中获取数据。

let p1 = new Promise(resolve => {
  setTimeout(resolve, 1000, '123');
})

let p2 = new Promise(resolve => {
  setTimeout(resolve, 2000, '456');
})

Promise.all([p1, p2]).then(res => {
  console.log(res);			// 2s后打印['123', '456']
})

Promise.race()

Promise.race接受一个包含多个promise对象的数组,只要任务完成就返回结果,无论结果是成功还是失败。可以根据方法名的字面意思来理解,看成是数组中的Promise对象进行竞赛,先返回的那个值就是Promise最终的返回值。

// Promise.race() 执行先完成的Promise回调
// 请求图片资源 如果超时则通知用户
function requestImg(url) {
  return new Promise(function(resolved, rejected) {
    const img = new Image()
    img.onload = function() {
      resolved(img)
    }
    img.src = url
  })
}


function timeout() {
  return new Promise(function(resolved, rejected) {
    setTimeout(() => {
      rejected(new Error('图片请求超时'))
    }, 10000)
  })
}

// 接收一个包含promise对象的数组
Promise.race([requestImg('https://img0.baidu.com/it/u=1705694933,4002952892&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1675098000&t=01a5f2c60b89ef81f51c826c9d543b61'), timeout()])
.then(img => {
  console.log(img)
  document.body.appendChild(img)
}).catch(err => {
  console.log(err)
})

Promise.all()与Promise.race()的对比

Promise.race() 和 Promise.all() 一样也是包装多个 Promise 实例,返回一个新的 Promise 实例,只是返回的结果不同。Promise.all() 是所有的任务都处理完才会得到结果,而 Promise.race() 是只要任务成功就返回结果,无论结果是成功还是失败。Promise.all() 在处理多个任务时是非常有用的,比如用 Promise.all() 并发的请求接口,我们希望得到所以接口请求回来的数据之后再去做一些逻辑,这样我们就不需要维护一个数据来记录接口请求有没有完成,而且这样请求的好处是最大限度地利用浏览器的并发请求,节约时间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值