前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >写给前端小白的「Promise备忘手册」!(建议收藏)

写给前端小白的「Promise备忘手册」!(建议收藏)

作者头像
HoMeTown
发布2022-10-26 08:56:28
4000
发布2022-10-26 08:56:28
举报
文章被收录于专栏:秃头开发头秃了

前言

大家好,我是HoMeTown,Promise想必大家都知道,在平时的开发工程中也经常会有用到,但是Promise作为ES6的重要特性,其实还拥有很多丰富的知识,本文面向比较初级一些的同学,可以帮你搞懂Promise到底做了什么,顺便起到一个备忘录的作用。

Promise?

Promsie中文直译承诺,其实也很好理解,就是无论这个异步任务最后的结果怎么样,我承诺会给你一个结果。

Promise在JavaScript中是一个处理异步代码的解决方案,他的出现解决了JavaScript异步编程回调地狱的问题(此处 que一下wxapi)。

Promise对象代表一个异步操作,有三种状态:pending(进行中) fulfilled(已成功) rejected(已失败)

一个Promsie实例必然处于上述的三个状态直译。

Promise的运行机制

当Promise被实例化后,其实例会处于pending状态,一般情况下,遇到以下操作,Promise的状态会被改变:

  1. 执行resolve
  2. 执行reject
  3. 出现报错

下面举个例子:

代码语言:javascript
复制
const p1 = new Promise((resolve, reject) => {
    resolve('成功')
    console.log('这里还能执行吗?-- p1')
    reject('失败')
    console.log('这里呢?-- p1')
  })
  console.log(p1,'p1')
  
  const p2 = new Promise((resolve, reject) => {
    reject('失败')
    resolve('成功')
    console.log('这里还能执行吗?-- p2')
  })
  console.log(p2, 'p2')
  
  const p3 = new Promise((resolve, reject) => {})
  console.log(p3, 'p3')
  
  const p4 = new Promise((resovle, reject) => {
    throw 'error'
  })
  console.log(p4, 'p4')

  const p5 = new Promise((resovle, reject) => {
    throw 'error'
    resolve('成功')
    reject('失败')
  })
  console.log(p5, 'p5')

  const p6 = new Promise('测试')
  console.log(p6, 'p6')

执行结果如下:

通过上图中的执行结果我们可以发现:

  1. new Promise 返回了一个Promise实例
  2. 传入Promise构造函数中的执行函数,会被立即执行,且拥有了两个参数resolve reject
  3. resolve操作 之后 PromiseState(状态) 会变成 flufilled, PromiseResult 为 resolve的参数
  4. reject操作 之后 PromiseState(状态) 会变成 rejected,PromiseResult 为 rejected的参数
  5. 报错之后 之后 PromiseState(状态) 会变成 rejected,PromiseResult 为 报错信息
  6. 如果没有执行resolve/reject,也没有出现报错,PromiseState(状态) 会保持 pending,PromiseResult 为 undefined
  7. 一旦执行resolve/reject,或者出现报错Promise会修改Promise实例的PromiseState & PromiseResult,后续的代码还会继续执行

Promise的使用

Promise作为一个构造函数可以被new关键字进行实例化,并在.then.catch分别取到成功和失败的结果。

代码语言:javascript
复制
p1.then(res => { console.log(res, '成功')}).catch(err => {console.log('失败', err)})

Promise封装请求器

代码语言:javascript
复制
function request({ method = "GET", url = "", data = {}, timeout = 10000 }) {
  const xhr = new XMLHttpRequest();
  return new Promise((resolve, reject) => {
    xhr.onreadystatechange = function () {
      if (xhr.readyState !== 4) return reject("xhr readyState error");
      if (xhr.timeout > timeout) return reject("request timout");
      if (xhr.status === 200) {
        resolve(JSON.parse(xhr.responseText));
      } else {
        reject(xhr.statusText);
      }
    };
    xhr.open(method, url);
    xhr.send(data);
  });
}

测试请求器:

代码语言:javascript
复制
// 测试请求器request({
  method: "GET",
  url: "https://api.apiopen.top/api/getHaoKanVideo?page=0&size=2",
}).then((res) => {
  console.log(res, "获取数据成功");
});

结果如下:

Promise原型上的方法

Promise.prototype.then

Promise.prototype具有then方法,也就是说,每一个Promsie实例对象都可以调用then方法得到Promsie成功的结果。

then方法的第一个参数是flufilled状态的回调函数,第二个参数是rejected状态的回调函数,举个栗子:

代码语言:javascript
复制
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('good')
    reject('bad'); // 这里不会被执行
  }, 1000);
});
p1.then(  (res) => {
    console.log(res, "成功");
  },  (err) => {
    console.log(err, "失败");
  }
);

执行结果如下:

Promise.prototype.catch

catch() 方法返回一个Promise,用捕捉指定错误并且处理错误。它的行为与调用Promise.prototype.then(_, onRejected) 相同,举个栗子:

代码语言:javascript
复制
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("bad");
  }, 1000);
});
p1.catch(err => {
    console.log(err)
})

执行结果如下:

then链

有趣的是,then方法也返回了一个Promsie实例,那就意味着,可以继续执行.then进行下一次的结果获取,像这样:

代码语言:javascript
复制
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("good");
    reject("bad");
  }, 1000);
});
p1.then((res) => {
  console.log(res, "then1");
}).then(res => {
    console.log(res, 'then2') // undefined 'then2'})

then方法中,你可以通过return决定下一次的结果是什么:

  • 返回基本数据类型或者引用数据类型,下一次接受该数据,状态为flufilled,可继续.then
  • 返回一个Promsie
    • 状态为flufilled,可继续执行.then
    • 状态为pending,不会继续执行.then,直到当前Promise实例得到一个有效的状态
    • 状态为rejected,不会继续执行.then,直接走到.catch
  • 什么都没返回,执行.then,结果为undefined
  • 出现报错,直接走到.catch

Promise.prototype.finally

finally方法用于不管结果如何,都会执行的操作,可以避免相同的逻辑在then&catch重复写的情况,举个栗子:

代码语言:javascript
复制
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("bad");
  }, 1000);
});
p1.then((res) => {
  console.log(res, "成功");
})
  .catch((err) => {
    console.log(err, "失败");
  })
  .finally(() => {
    console.log("不管成功不成功");
  });

执行结果如下:

Promise构造函数上的方法

Promise的prototype上也有一些函数可以使用,比如(race、all、any、race等):

Promise.resolve

Promise.resolve方法不是excutefunc上的resovle方法,而是原型上的方法,该方法接受一个参数,返回一个状态为fulfilled 的 Promise实例,如果参数为基本类型或者引用类型,则PromiseResult为传递进来的参数,举个栗子

代码语言:javascript
复制
const pstring = Promise.resolve('HoMeTowm')console.log(pstring,'字符串 Promise实例')const pnumber = Promise.resolve(123)console.log(pnumber,'数字 Promise实例')const pboolean = Promise.resolve(true)console.log(pboolean,'布尔值 Promise实例')const pobject = Promise.resolve({name: 'HoMeTowm'})console.log(pobject,'对象 Promise实例')console.log('......')

执行结果如下:

如果传递进来的是一个Promise实例,则完整的返回这个Promise实例,举个栗子:

代码语言:javascript
复制
const p1 = new Promise((resolve) => {
    resolve('Promise 实例: p1')
})const ppromise = Promise.resolve(p1)console.log(ppromise, 'Promise.resolve的实例:ppromise')

执行结果如下:

如果没有传参数,返回PromiseResultundefined的Promise实例:

代码语言:javascript
复制
const pundefined = Promise.resolve()console.log(pundefined)

执行结果如下:

Promise.reject

Promise.reject方法相同,也会返回一个Promise实例,不同的是PromiseStatusrejectd,用上面的栗子进行测试:

代码语言:javascript
复制
const pstring = Promise.reject('HoMeTowm')console.log(pstring,'字符串 Promise实例')const pnumber = Promise.reject(123)console.log(pnumber,'数字 Promise实例')const pboolean = Promise.reject(true)console.log(pboolean,'布尔值 Promise实例')const pobject = Promise.reject({name: 'HoMeTowm'})console.log(pobject,'对象 Promise实例')console.log('......')

执行结果如下:

Promise.all

Promise.all方法,可以发起并发请求,然后再所有Promise都脱离pending状态后,统一返回结果,接受一个数组作为参数,数组中的项为Promise实例(如果不是的话,传啥返回啥),返回一个Promise实例,PromiseResult每个实例对应的结果PromiseState所有的实例未脱离pending之前为pending,举个例子:

代码语言:javascript
复制
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log("p1 resolve执行");
    resolve("p1 的结果");
  }, 1000);
});const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log("p2 resolve执行");
    resolve("p2 的结果");
  }, 2000);
});const pnumber = 510const pall = Promise.all([p1, p2, pnumber]);console.log("promise.all 的结果未完成:", pall);
pall.then((res) => {
  console.log(res, "全部的结果");
  console.log("promise.all 的结果已完成:", pall);
});

执行结果如下:

数组中如果有一个失败,则返回失败的结果,只要失败了就返回!举个栗子:

代码语言:javascript
复制
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('p1 还能执行')
    throw "哎呀,p1报错了";
  }, 1000);
});const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('p2 还能执行')
    resolve("p2 的结果");
  }, 2000);
});const preject = Promise.reject("Promsie.reject 失败");const pall = Promise.all([p2, p1, preject]);console.log("promise.all 的结果未完成:", pall);
pall
  .then((res) => {
    console.log(res, "全部的结果");
    console.log("promise.all 的结果已完成:", pall);
  })
  .catch((err) => {
    console.log(err, "失败了 嘤嘤嘤");
  });

执行结果如下:

Promise.allSettled

Promise.allSettled用法与Promise.all相同,不同的是,Promise.allSettled不会因为有一个失败,就走到catch,而是会走到then,并告诉你,哪个失败了,那个成功了,举个栗子:

代码语言:javascript
复制
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
     reject('p1 失败')
  }, 1000);
});const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("p2 成功");
  }, 2000);
});const pall = Promise.allSettled([p2, p1, Promise.reject(1)]);console.log("promise.allSettled 的结果未完成:", pall);
pall
  .then((res) => {
    console.log(res, "全部的结果");
    console.log("promise.allSettled 的结果已完成:", pall);
  })
  .catch((err) => {
    console.log(err, "失败了 嘤嘤嘤");
  });

执行结果如下:

Promise.race

Promise.race与其字面意思相同,竞速,即哪个先完成,就以哪个为结果,参数与Promise.all相同,举个栗子:

代码语言:javascript
复制
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
     reject('p1 失败')
  }, 1000);
});const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("p2 成功");
  }, 2000);
});const prace = Promise.race([p2, p1]);

prace.then(res => {
    console.log(res,'成功')
}).catch(err => {
    console.log(err, '失败')
})

执行结果如下:

Promise.any

Promise.any方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例,有一个子实例成功就算成功,全部子实例失败才算失败,返回AggregateError: All promises were rejected,举个栗子:

代码语言:javascript
复制
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
     reject('p1 失败')
  }, 1000);
});const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("p2 成功");
  }, 2000);
});const prace = Promise.any([p2, p1]);

prace.then(res => {
    console.log(res,'成功')
}).catch(err => {
    console.log(err, '失败')
})

执行结果如下:

p2改为reject之后,执行结果如下:

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-09-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 秃头开发头秃了 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Promise?
  • Promise的运行机制
  • Promise的使用
  • Promise封装请求器
  • Promise原型上的方法
    • Promise.prototype.then
      • Promise.prototype.catch
        • then链
          • Promise.prototype.finally
          • Promise构造函数上的方法
            • Promise.resolve
              • Promise.reject
                • Promise.all
                  • Promise.allSettled
                    • Promise.race
                      • Promise.any
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档