JS中Promise的使用及封装方式

2023-03-06 10:35:43

目录Promise是什么Promise的特点Promise的缺点Promise的原理Promise的方法1.Promise.prototype.then()2.Promise.proto...

目录
Promise 是什么
Promise 的特点
Promise 的缺点
Promise 的原理
Promise 的方法
1. Promise.prototype.then()
2. Promise.prototype.catch()
3. Promise.prototype.finally()
4. Promise.all()
5. Promise.race()
5. Promise.allSettled()
Promise 的简单封装
总结

Promise 是什么

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise 的特点

1. 对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 Promise 这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变

2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 pending 变为 fulfilled 和从 pending 变为 rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

3. 将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数(回调地狱)

Promise 的缺点

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

Promise 的原理

ES6 规定,Promise 对象是一个构造函数,用来生成 Promise 实例。通过在函数内部 return 一个 Promise 对象的实例,这样就可以使用 Promise 的属性和方法进行下一步操作了。    

Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署

const promise = new Promise(function(resolve, reject) {
 if (/* 异步操作成功 */){
  resolve(value)
 } else {
  reject(error)
 }
})

Promise 的方法

1. Promise.prototype.then()

then()方法就是把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。

而 Promise的优势就在于这个链式调用。

我们可以在 then 方法中继续写 Promise 对象并返回,然后继续调用 then 来进行回调操作。

resolve 的用法

let promise = new Promise(function(resolve, reject) {
 console.log('Promise')
 resolve('已完成')
});

promise.then(function(data) {
 console.log('resolved.',data)
})

console.log('Hi!')

// Promise
// Hi!
// resolved. 123

reject 的用法

reject 方法就是把 Promise 的状态置为已失败(Rejected),这时 then 方法执行“失败”情况的回调(then 方法的第二参数)

let promise = new Promise(function(resolve, reject) {
 reject('NO')
});

promise.then(function(data) {
 console.log('resolved.',data)
},function(data){
 console.log('rejected.',data)
})

// rejected. NO

2. Promise.prototype.catch()

如果异步操作抛出错误,当前 Promise 对象状态就会变为 rejected,就会调用 catch 方法指定的回调函数,处理这个错误。

另外,then 方法指定的回调函数,如果运行中抛出错误,也会被 catch 方法js捕获。

catch 方法返回的也是一个 Promise 对象,因此后面还可以接着调用then方法。

const promise = new Promise(function(resolve, reject) {
 resolve('OK')
})

promise.then(function(data) {
 console.log(data)
 console.log(num)
}).catch(function(err) {
 console.log(err)
})

// OK
// ReferenceError: num is not defined

3. Promise.prototype.finally()

finally 方法用于指定不管 Promise 对象最后状态如何,在执行完 then 或 cathttp://www.cppcns.comch 指定的回调函数以后,都会执行 finally 方法指定的回调函数。

finally 方法的回调函数不接受任何参数,在 finally 方法里面的操作,与状态无关,不依赖于 Promise 的执行结果。

// 服务器使用 Promise 处理请求,然后使用 finally 方法关掉服务器
server.listen(port)
 .then(function () {
  // ...
 })
 .finally(server.stop)

4. Promise.all()

Promise 的 all 方法(传入一个数组,每一项分别是一个 Promise 实例)提供了并行执行异步操作的能力,并且在所有异步操作执行完(所有实例的状态都变成 fulfilled)或者 只要有一个 Promise 实例的状态变为 reject,Promise.all 的状态就会变为 reject,然后执行回调。可以将数组里的 Promise 看成是 “与” 关系。

应用场景:打开网页时,预先加载需要用到的各种资源如图片、flash 以及各种静态文件。所有的都加载完后,我们再进行页面的初始化

//买作业本
function cutUp() {
 console.log('挑作业本')
 var p = new Promise(function(resolve, reject) { //做一些异步操作
 console.log('挑好购买作业本')
  resolve('新的作业本')
 })
 return p
}
   
//买笔
function boil() {
 console.log('挑笔芯')
 var p = new Promise(function(resolve, reject) { //做一些异步操作
  console.log('挑好购买笔芯')
  resolve('新的笔芯')
 });
 return p
}

Promise.all([cutUp(),boil()]).then(function(res) {
 console.log("写作业的工具都买好了")
 console.log(res)
})

// 挑作业本
// 挑好购买作业本
// 挑笔芯
// 挑好购买笔芯
// 写作业的工具都买好了
// ["新的作业本", "新的笔芯"]

5. Promise.race()

javascript

Promise.race 方法( 传入一个数组,每一项分别是 Promise 实例 )的用法与 all 一样,异步操作同样是并行执行的。只不过 all 是等所有异步操作都执行完毕后才执行 then 回调。race 可以看到 是 “或” 关系,只要有一个异步操作执行完毕,就会立刻执行 then 回调。

应用场景:用 race 给某个异步请求设置超时时间,并且在超时后执行相应的操作

//买作业本
function cutUp() {
 console.log('挑作业本')
 var p = new Promise(function(resolve, reject) { //做一些异步操作
 console.log('挑好购买作业本')
  resolve('新的作业本')
 })
 return p
}
   
//买笔
function boil() {
 console.log('挑笔芯')
 var p = new Promise(function(resolve, reject){ //做一些异步操作
  console.log('挑好购买笔芯')
  resolve('新的笔芯')
 })
 return p
}

Promise.race([cutUp(),boil()]).then(function(res){
 console.log("写作业的工具都买好了")
 console.log(res)
})

// 挑作业本
// 挑好购买作业本
// 挑笔芯
// 挑好购买笔芯
// 写作业的工具都买好了
// 新的作业本

5. Promise.allSettled()

Promise.allSettled() 方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例 。

只有等到所有这些参数实例都返回结果,不管是 fulfilled 还是 rejected,包装实例才会结束。

Promise.allSettled()的返回值该是一个数组,数组里每个对象都有 status 属性,该属性的值只可能是字符串 fulfilled 或字符串rejected。

fulfilled 时,对象有 value 属性,rejected 时有 reason 属性,对应两种状态的返回值。

应用场景:不关心异步操作的结果,只确保所有异步操作都结束

//买作业本
function cutUp() {
 console.log('挑作业本')
 var p = new Promise(function(resolve, reject) { //做一些异步操作
 console.log('挑好购买作业本')
  resolve('新的作业本')
 })
 return p
}
   
//买笔
function boil() {
 console.log('挑笔芯')
 var p = new Promise(function(resolve, reject){ //做一些异步操作
  console.log('挑好购买笔芯')
  reject('购买不了,没钱了')
 })
 return p
}

Promise.allSettled([cutUp(),boil()]).then(function(res){
 console.log("写作业的工具没有买齐")
 console.log(res)
})

// 挑作业本
// 挑好购买作业本
// 挑笔芯
// 挑好购买笔芯
// 写作业的工具没有买齐
// [
//  {status: "fulfilled", value: "新的作业本"}
//  {status: "rejected", reason: "购买不了,没钱了"}
// ]

Promise 的简单封装

function promiseM(callback) {
  this.status = 'pendding'
  this.msg = ''

  callback((data) => {
    this.status = 'resolve'
    this.msg = data
  },(err) => {
  if (this.status === 'resolve') return
    this.status = 'reject'
    this.msg = err
  })
}

promiseM.prototype.then = function () {
  let cb = arguments
  let that = this
  let timer = setInterval(function () {
    if(that.status == 'resolve') {
      cb[0](that.msg)
      clearInterval(timer)
    } else if(that.status == 'reject') {
     if(!cb[1]) {
      clearInterval(timer)
        throw that.msg + ' No Exit'
     } else {
      cb[1](that.msg)
       clearInterval(timer)
     }
    }
  }, 500)
}

function fn() {
  return new promiseM(function (resolve, reject) {
    resolve('success')
  })
}

fn().then(function (res) {
  console.log(res)
})

// success

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。