1. 图示

思维导图链接 https://www.zhixi.com/view/23ff2291

2. 使用promise原因

在没有promise的时候,一直使用setTimeout函数,这样就会造成回调地狱。

3. 基本状态

promise 有三种状态

  1. pending(此时 promise还没有调用完成)
  2. fulfilled(promise 调用完成,状态是成功了)
  3. rejected(promise 调用完成,状态是失败了)

Promise 状态一旦从pending转换为fulfilled或者rejected, 那么状态将不会再次改变

4. 类上的常用方法

Promise 类上方法也是经常使用的

  1. Promise.resolve()
传入值 返回值
传入一个promise res值 返回res, 直接promise 结果值
传入一个promise rej 值 返回为rej类型, 直接promise 结果值
传入一个基本类型值 返回res类型, 直接获取值

结论 resolve 传入rej 类型时,返回也是rej。但是无论传入什么都被解析为最终结果

  1. Promise.reject()
传入值 返回值
传入一个promise res值 直接是rej ,直接返回promise
传入一个promise rej 值 直接是rej,  直接返回promise
传入一个基本类型值 返回res类型, 直接获取值

结论 reject 传入什么都是rej,且返回值就是传入值

  1. Promise.all() **传入值必须有Iterator接口**
var p = Promise.all([p1,p2,p3]);
传入一个promise数组(如果是基本类型直接就是 res类型的Promise), 等待所有的promise 完毕,但是有一个promise为rej 就直接返回 失败结果, 不再等待全部执行完毕。
  1. Promise.race() **传入值必须有Iterator接口**
const p = Promise.race([p1, p2, p3]);
是 Promise.race 只要传入的 Promise 对象,有一个状态变化了(无论对错),就会立即结束,而不会等待其他 Promise 对象返回。
  1. Promise.allSettled() **传入值必须有Iterator接口**
const p = Promise.allSettled([p1, p2, p3]);
传入一个promise数组(如果是基本类型直接就是 res类型的Promise), 无论是正确还是错误,最后整合为一个数组,全部返回。返回的值代表每个promise的状态和结果,错误的就是 错误状态和错误信息。

5. 原型链式调用返回值

  1. then resolve返回, then reject 返回, catch 返回 三者 return 后是一样的
三者一样
1.传入一个promise res值   返回res类型, 直接promise 结果值
2.传入一个promise rej 值   直接是rej,  直接promise 结果值
3.传入一个基本类型值      返回res类型, 直接获取值
  1. finally 返回

不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。

finally 是没有return (返回值的),且不对当前一次的返回值造成影响。且finally 是没有任何传参的。

6.(then 里面的 reject) 和 catch 的区别

1.catch 方法可以捕获到 catch 之前整条 promise 链路上所有抛出的异常。

2.then 方法的第二个参数捕获的异常依赖于上一个 Promise 对象的执行结果。

如果是promise内部报错 reject 抛出错误后,then 的第二个参数就能捕获得到,如果then的第二个参数不存在,则catch方法会捕获到。

如果是then的第一个参数函数 resolve 中抛出了异常,即成功回调函数出现异常后,then的第二个参数reject 捕获捕获不到,catch方法可以捕获到。

7. async await 合并使用

1.await 同一行后面的内容对应 Promise 主体内容,即同步执行的
2.( 重点) await 下一行的内容对应 then()里面的内容,是异步执行的,
其实也是await这行执行的相当于then方法。对await右边的值进行返回
示例:async function asyncFun() {console.log('async1 start');await 111;console.log('async1 inner');}asyncFun();console.log('script end');3.await 同一行后面应该跟着一个 Promise 对象,如果不是,需要转换(如果是常量会自动转换)
4.async 函数的返回值还是一个 Promise 对象

8. 使用try catch 的注意事项

try catch 是传统的异常捕获方式,这里只能捕获同步代码的异常,并不能捕获异步异常,因此无法对 Promise 进行完整的异常捕获。

总结,看道题


function promise2() {  return new Promise((resolve) => {  console.log('promise2 start');  resolve();  })
}
function promise3() {  return new Promise((resolve) => {  console.log('promise3 start');  resolve();  })
}
function promise4() {  return new Promise((resolve) => {  console.log('promise4 start');  resolve();  }).then(() => {  console.log('promise4 end');  })
}
async function asyncFun() {  console.log('async1 start');  await promise2();  console.log('async1 inner');  await promise3();  console.log('async1 end');
}
setTimeout(() => {  console.log('setTimeout start');  promise1();  console.log('setTimeout end');
}, 0);
asyncFun();
promise4();
console.log('script end');

9.介绍下 promise 的特性、优缺点,内部是如何实现的,动手实现 Promise

1)Promise基本特性

  • 1、Promise有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)
  • 2、Promise对象接受一个回调函数作为参数, 该回调函数接受两个参数,分别是成功时的回调resolve和失败时的回调reject;另外resolve的参数除了正常值以外, 还可能是一个Promise对象的实例;reject的参数通常是一个Error对象的实例。
  • 3、then方法返回一个新的Promise实例,并接收两个参数onResolved(fulfilled状态的回调);onRejected(rejected状态的回调,该参数可选)
  • 4、catch方法返回一个新的Promise实例
  • 5、finally方法不管Promise状态如何都会执行,该方法的回调函数不接受任何参数
  • 6、Promise.all()方法将多个多个Promise实例,包装成一个新的Promise实例,该方法接受一个由Promise对象组成的数组作为参数(Promise.all()方法的参数可以不是数组,但必须具有**Iterator接口**,且返回的每个成员都是Promise实例),注意参数中只要有一个实例触发catch方法,都会触发Promise.all()方法返回的新的实例的catch方法,如果参数中的某个实例本身调用了catch方法,将不会触发Promise.all()方法返回的新实例的catch方法
  • 7、Promise.race()方法的参数与Promise.all方法一样,参数中的实例只要有一个率先改变状态就会将该实例的状态传给Promise.race()方法,并将返回值作为Promise.race()方法产生的Promise实例的返回值
  • 8、Promise.resolve()将现有对象转为Promise对象,如果该方法的参数为一个Promise对象,Promise.resolve()将不做任何处理;如果参数thenable对象(即具有then方法),Promise.resolve()将该对象转为Promise对象并立即执行then方法;如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的Promise对象,状态为fulfilled,其参数将会作为then方法中onResolved回调函数的参数,如果Promise.resolve方法不带参数,会直接返回一个fulfilled状态的 Promise 对象。需要注意的是,立即resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。
  • 9、Promise.reject()同样返回一个新的Promise对象,状态为rejected,无论传入任何参数都将作为reject()的参数

2)Promise优点

  • 统一异步 API

    • Promise 的一个重要优点是它将逐渐被用作浏览器的异步 API ,统一现在各种各样的 API ,以及不兼容的模式和手法。
  • Promise 与事件对比

    • 和事件相比较, Promise 更适合处理一次性的结果。在结果计算出来之前或之后注册回调函数都是可以的,都可以拿到正确的值。 Promise 的这个优点很自然。但是,不能使用 Promise 处理多次触发的事件。链式处理是 Promise 的又一优点,但是事件却不能这样链式处理。
  • Promise 与回调对比

    • 解决了回调地狱的问题,将异步操作以同步操作的流程表达出来。
  • Promise 带来的额外好处是包含了更好的错误处理方式(包含了异常处理),并且写起来很轻松(因为可以重用一些同步的工具,比如 Array.prototype.map() )。

3)Promise缺点

  • 1、无法取消Promise,一旦新建它就会立即执行,无法中途取消。
  • 2、如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
  • 3、当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
  • 4、Promise 真正执行回调的时候,定义 Promise 那部分实际上已经走完了,所以 Promise 的报错堆栈上下文不太友好。

4)简单代码实现 最简单的Promise实现有7个主要属性, state(状态), value(成功返回值), reason(错误信息), resolve方法, reject方法, then方法

class Promise{constructor(executor) {this.state = 'pending';this.value = undefined;this.reason = undefined;let resolve = value => {if (this.state === 'pending') {this.state = 'fulfilled';this.value = value;}};let reject = reason => {if (this.state === 'pending') {this.state = 'rejected';this.reason = reason;}};try {// 立即执行函数executor(resolve, reject);} catch (err) {reject(err);}}then(onFulfilled, onRejected) {if (this.state === 'fulfilled') {let x = onFulfilled(this.value);};if (this.state === 'rejected') {let x = onRejected(this.reason);};}
}
复制代码

5)面试够用版

function myPromise(constructor){ let self=this;self.status="pending" //定义状态改变前的初始状态 self.value=undefined;//定义状态为resolved的时候的状态 self.reason=undefined;//定义状态为rejected的时候的状态 function resolve(value){//两个==="pending",保证了了状态的改变是不不可逆的 if(self.status==="pending"){self.value=value;self.status="resolved"; }}function reject(reason){//两个==="pending",保证了了状态的改变是不不可逆的if(self.status==="pending"){self.reason=reason;self.status="rejected"; }}//捕获构造异常 try{constructor(resolve,reject);}catch(e){reject(e);}
}
myPromise.prototype.then=function(onFullfilled,onRejected){ let self=this;switch(self.status){case "resolved": onFullfilled(self.value); break;case "rejected": onRejected(self.reason); break;default: }
}// 测试
var p=new myPromise(function(resolve,reject){resolve(1)});
p.then(function(x){console.log(x)})
//输出1
复制代码

6)大厂专供版

const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
const resolvePromise = (promise, x, resolve, reject) => {if (x === promise) {// If promise and x refer to the same object, reject promise with a TypeError as the reason.reject(new TypeError('循环引用'))}// if x is an object or function,if (x !== null && typeof x === 'object' || typeof x === 'function') {// If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.let calledtry { // If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.let then = x.then // Let then be x.then// If then is a function, call it with x as thisif (typeof then === 'function') {// If/when resolvePromise is called with a value y, run [[Resolve]](promise, y)// If/when rejectPromise is called with a reason r, reject promise with r.then.call(x, y => {if (called) returncalled = trueresolvePromise(promise, y, resolve, reject)}, r => {if (called) returncalled = truereject(r)})} else {// If then is not a function, fulfill promise with x.resolve(x)}} catch (e) {if (called) returncalled = truereject(e)}} else {// If x is not an object or function, fulfill promise with xresolve(x)}
}
function Promise(excutor) {let that = this; // 缓存当前promise实例例对象that.status = PENDING; // 初始状态that.value = undefined; // fulfilled状态时 返回的信息that.reason = undefined; // rejected状态时 拒绝的原因 that.onFulfilledCallbacks = []; // 存储fulfilled状态对应的onFulfilled函数that.onRejectedCallbacks = []; // 存储rejected状态对应的onRejected函数function resolve(value) { // value成功态时接收的终值if(value instanceof Promise) {return value.then(resolve, reject);}// 实践中要确保 onFulfilled 和 onRejected ⽅方法异步执⾏行行,且应该在 then ⽅方法被调⽤用的那⼀一轮事件循环之后的新执⾏行行栈中执⾏行行。setTimeout(() => {// 调⽤用resolve 回调对应onFulfilled函数if (that.status === PENDING) {// 只能由pending状态 => fulfilled状态 (避免调⽤用多次resolve reject)that.status = FULFILLED;that.value = value;that.onFulfilledCallbacks.forEach(cb => cb(that.value));}});}function reject(reason) { // reason失败态时接收的拒因setTimeout(() => {// 调⽤用reject 回调对应onRejected函数if (that.status === PENDING) {// 只能由pending状态 => rejected状态 (避免调⽤用多次resolve reject)that.status = REJECTED;that.reason = reason;that.onRejectedCallbacks.forEach(cb => cb(that.reason));}});}// 捕获在excutor执⾏行行器器中抛出的异常// new Promise((resolve, reject) => {//     throw new Error('error in excutor')// })try {excutor(resolve, reject);} catch (e) {reject(e);}
}
Promise.prototype.then = function(onFulfilled, onRejected) {const that = this;let newPromise;// 处理理参数默认值 保证参数后续能够继续执⾏行行onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;onRejected = typeof onRejected === "function" ? onRejected : reason => {throw reason;};if (that.status === FULFILLED) { // 成功态return newPromise = new Promise((resolve, reject) => {setTimeout(() => {try{let x = onFulfilled(that.value);resolvePromise(newPromise, x, resolve, reject); //新的promise resolve 上⼀一个onFulfilled的返回值} catch(e) {reject(e); // 捕获前⾯面onFulfilled中抛出的异常then(onFulfilled, onRejected);}});})}if (that.status === REJECTED) { // 失败态return newPromise = new Promise((resolve, reject) => {setTimeout(() => {try {let x = onRejected(that.reason);resolvePromise(newPromise, x, resolve, reject);} catch(e) {reject(e);}});});}if (that.status === PENDING) { // 等待态
// 当异步调⽤用resolve/rejected时 将onFulfilled/onRejected收集暂存到集合中return newPromise = new Promise((resolve, reject) => {that.onFulfilledCallbacks.push((value) => {try {let x = onFulfilled(value);resolvePromise(newPromise, x, resolve, reject);} catch(e) {reject(e);}});that.onRejectedCallbacks.push((reason) => {try {let x = onRejected(reason);resolvePromise(newPromise, x, resolve, reject);} catch(e) {reject(e);}});});}
};

Promise(微任务)- 让你看完就懂相关推荐

  1. 看完弄懂,明年至少加 5K

    看完弄懂,明年至少加 5K

  2. 网络通过猫传输到计算机,网络直接从光猫出来好还是接个路由器再接入电脑好?看完搞懂了...

    网络直接从光猫出来好还是接个路由器再接入电脑好?看完搞懂了 宽带网络现在是家家户户不可缺少的"硬件"之一,现在即便是老一辈的人家中安装宽带都成了必需品.有些偏好用电脑来上网的朋友可 ...

  3. 高铁、动车到底啥区别?看完彻底懂了(组图)

    摘自:网易新闻 (原标题:高铁.动车到底啥区别?看完彻底懂了(组图)) 高铁与动车的区别到底在哪里?磁悬浮列车又是什么鬼?今天给你讲讲清楚! 高铁.动车到底啥区别?看完彻底懂了 一.普通列车与高铁钢轨 ...

  4. 华为mate10pro以后能上鸿蒙吗,华为Mate10和Mate10 Pro差别一览 怎么选看完就懂

    华为Mate10和Mate10 Pro差别一览 怎么选看完就懂上周五华为正式发布了今年的两款重磅旗舰Mate10和Mate10 Pro.与上代产品不同,此次Mate10系列的两款产品无论是在外观还是一 ...

  5. 新手入门,数控刀具上的代码怎么认?看完就懂了!

    新手入门,数控刀具上的代码怎么认?看完就懂了! 按照不同的刀具类型对刀具分组: 类别组1 xxyyy(铣刀类): 110 球面铣刀 (圆柱型铣刀,其后的字母y代表铣刀直径,以下略同) 120 立铣刀 ...

  6. 为什么会显示有人正在使用计算机,微信“对方正在输入”为什么有时出现?有时不出现?看完才懂了.....

    原标题:微信"对方正在输入"为什么有时出现?有时不出现?看完才懂了.. 生活中有很多美好的事情 手机电量满格 您的快递正在派送 换季衣服里翻出毛爷爷 与喜欢的人聊天显示" ...

  7. java开发用i5还是i7,i7比i5更强!为什么内行人都选i5而不选i7?看完瞬间懂了

    i7比i5更强!为什么内行人都选i5而不选i7?看完瞬间懂了 2020-11-19 11:18:08 4点赞 0收藏 0评论 许多人认为i7比i5更好,那么有什么好呢?让我们先看一下区别. i7使用四 ...

  8. Callable和Runnable的区别(面试常考),看完就懂

    Callable和Runnable的区别(面试常考),看完就懂 Callable 接口 测试类 Runnable 接口 测试类 两者的区别 补充Executor框架 Callable 接口 publi ...

  9. android 7 plus,手机别瞎买,iPhone7plus相当于什么档次的安卓机?看完就懂了!

    手机别瞎买,iPhone7plus相当于什么档次的安卓机?看完就懂了! 作为此前一直比较受欢迎的苹果手机,一直是安卓手机的大力比拼的对象,目前已经有的安卓手机能够在拍照的性能上超过苹果手机了,虽然说在 ...

  10. 看完就懂webpack打包原理

    目录 什么是 webpack ? webpack 核心概念 Entry Output Module Chunk Loader Plugin webpack 构建流程 实践加深理解,撸一个简易 webp ...

最新文章

  1. [转]产品需求文档(PRD)的写作
  2. Android拖拽图片的实现
  3. ssh框架点击按钮就404_设置404错误页面的5大关键因素
  4. Faster R-CNN理解、讨论
  5. 最大公约数(Greatest_Common_Divisor)
  6. hibernate by example 排除某些列
  7. sort+参数+linux,linux sort下令参数及用法详解
  8. 7搭建zabbix_监控03分布式监控Zabbix
  9. android 半边圆角背景,Android UI(一)Layout 背景局部Shape圆角设计
  10. CentOS下openssh版本降级
  11. 【转】Laplace 算子
  12. 基于OMAPL138/C6748 + SPARTAN-6 77GHz汽车防撞雷达信号处理平台设计
  13. 最新的中国姓氏重新洗牌:快来看看你的姓排第几?
  14. 解决margin坍塌
  15. Java读写Excel原来这么简单
  16. http代理IP的API接口要怎么使用
  17. 处理回收站“属性”不可用,没有“清空回收站”功能
  18. h5 实现一键复制到粘贴板 兼容iOS
  19. js - JavaScript
  20. Java程序员常用开发工具

热门文章

  1. 图形化编程与python的区别_计算机编程启蒙为什么要选图形化编程和python
  2. JAVAWEB校园二手平台项目
  3. 超级计算机图片高清,专业不止一点,vivo X50 Pro+后置四摄,高清1亿模式亮点十足...
  4. 7天内完成基础USB开发(2)——Pionway SDK简介
  5. Elasticsearch(十)【NEST高级客户端--搜索查询】
  6. CSS实现三角形、扇形、半圆以及圆形
  7. 支持homekit的智能生态有哪些?
  8. python手写汉字识别_用python实现手写数字识别
  9. 唱情歌的人和听的人为何那么认真?
  10. 手机网络邻居访问电脑_不是一个局域网手机怎么访问电脑