• 手写Promise


    1.想要进行手写Promise,首先需要知道promise 的基本特性及用法

    1. 有一个Promise构造函数,传入resolve和reject两个参数,是两个可以执行的函数
    2. promise有三种状态:pending等待,fulfilled成功,rejected失败
    3. 状态pending 一旦转为fulfilled或者rejected,不能再更改
    4. resolve()方法为成功处理方法,将状态由pending转为fulfilled,且传入参数value
    5. reject()方法为失败处理方法,将状态由pending转为rejected,且传入参数reason
    6. then()方法接受两个参数,分别为onFulfilled和onRejected函数,当状态由pending转为fulfilled后执行onFulfilled函数,由pending转为rejected后指向onRejected函数
    7. .then()方法支持链式调用,创建Promise实例后,可以通过实例一直调用.then()方法触发
    8. 静态方法的实现:Promise.resolve(),Promise.reject(),Promise.all()

    2.最终需要实现的效果:实现一个最基本的 promise案例

    1. let p = new Promise((resolve, reject) => {
    2. //支持异步操作
    3. setTimeout(function(){
    4. resolve('success')
    5. },1000);
    6. //resolve('success')
    7. // reject('error')
    8. })
    9. p.then(data => {
    10. console.log(data)
    11. return data;
    12. }).then(data=>{
    13. console.log(data);
    14. })

    3.实现步骤

    1. 需要创建一个Promise类,并且添加一个回调方法 callback,作为Promise 的参数
    2. callback接收resolve 和 reject 作为参数,并且resolve 和 reject为两个函数且分别接受参数value和reason
    3. 定义promise的三种状态,实现then方法:定义promise的初始状态pending(后面两个状态在执行对应函数resolve和reject后进行更改);实现then方法:传入两个函数参数(onFulfilled和onRejected)通过判断状态执行对应函数
    4. then()方法可实现异步操作(用定时器进行测试)
    5. 实现链式调用
    6. 添加静态方法

    3.1需要创建一个类,并且添加一个回调方法 callback,作为Promise 的参数

    1. class MPromise {
    2. constructor(callback) {
    3. // 执行回调函数
    4. callback();
    5. }
    6. }

    3.2callback接收resolve 和 reject 作为参数,并且resolve 和 reject为两个函数且分别接受参数value和reason

    1. class MPromise {
    2. constructor(callback) {
    3. // 定义成功返回参数。为什在构造器里面定义?
    4. this.value = undefined;
    5. // 定义失败返回参数
    6. this.reason = undefined;
    7. // 定义两个处理函数
    8. const resolve = (value) => {
    9. this.value = value;
    10. console.log(this.value);
    11. }
    12. const reject = (reason) => {
    13. this.reason = reason;
    14. }
    15. // 执行回调函数
    16. callback(resolve,reject);
    17. }
    18. }
    19. // MPromise类调用
    20. let p = new MPromise((resolve,reject)=>{
    21. resolve("success");
    22. });

    3.3定义和赋值promise的三种状态,实现then方法

    定义promise的初始状态pending(后面两个状态在执行对应函数resolve和reject后进行更改)

    实现then方法:传入

    1. class MPromise {
    2. constructor(callback) {
    3. // 定义成功返回参数。为什在构造器里面定义?
    4. this.value = undefined;
    5. // 定义失败返回参数
    6. this.reason = undefined;
    7. // 定义promise的初始状态pending(后面两个状态在执行对应函数后进行更改)
    8. this.state = 'pending';
    9. // 定义两个处理函数
    10. const resolve = (value) => {
    11. this.value = value;
    12. if(this.state === 'pending'){
    13. this.state = 'fulfilled';
    14. }
    15. }
    16. const reject = (reason) => {
    17. this.reason = reason;
    18. if(this.state === 'pending'){
    19. this.state = 'rejected';
    20. }
    21. }
    22. // 执行回调函数
    23. callback(resolve,reject);
    24. }
    25. // then方法时MPromise创建的实例调用的所以在constructor外
    26. // then()方法会接受两个函数参数(onFulfilled和onRejected)
    27. then(onFulfilled,onRejected){
    28. // 容错:onFulfilled,onRejected存在且为function时才能进行调用
    29. let onFulfilledState = onFulfilled ? typeof onFulfilled === 'function' : true; //判断如果onFulfilled传入了则继续判断是否为function函数,否则直接返回true传入什么返回什么
    30. let onRejectedState = onRejected ? typeof onRejected === 'function' : true;
    31. if(onFulfilledState && onRejectedState){
    32. // 根据对应状态调用不同的处理函数
    33. if(this.state === 'fulfilled'){
    34. onFulfilled(this.value);
    35. }
    36. if(this.state === 'rejected'){
    37. onRejected(this.value);
    38. }
    39. }
    40. }
    41. }
    42. // MPromise类调用
    43. let p = new MPromise((resolve,reject)=>{
    44. resolve("success");
    45. });
    46. p.then((data)=>{
    47. console.log(data);
    48. });

    3.4 then()方法可实现异步操作

    以上代码,如果加入定时器实现异步就会发现打印不了

    1. // MPromise类调用
    2. let p = new MPromise((resolve,reject)=>{
    3. setTimeout(function (){
    4. resolve("success");
    5. },1000)
    6. });
    7. p.then((data)=>{
    8. console.log(data);
    9. });

    给then方法加入返回值 new MPromise发现还是没有返回

    1. then(onFulfilled, onRejected) {
    2. return new MPromise((resolve, reject) => {
    3. // 容错:onFulfilled,onRejected存在且为function时才能进行调用
    4. let onFulfilledState = onFulfilled ? typeof onFulfilled === 'function' : true; //判断如果onFulfilled传入了则继续判断是否为function函数,否则直接返回true传入什么返回什么
    5. let onRejectedState = onRejected ? typeof onRejected === 'function' : true;
    6. if (onFulfilledState && onRejectedState) {
    7. // 根据对应状态调用不同的处理函数
    8. if (this.state === 'fulfilled') {
    9. resolve(onFulfilled(this.value));
    10. }
    11. if (this.state === 'rejected') {
    12. reject(onRejected(this.value));
    13. }
    14. }
    15. });
    16. }

     为什么加入了new MPromise()后还是没有返回?因为这里是通过setTimeout()进行异步操作,当执行then方法时,回调函数中的resolve()并未执行完成,就会导致状态一直是pending

    分析:发现p.then方法里面的函数不会触发,setTimeout()里面的resolve也没有执行

    为什么加入了new MPromise()后还是没有返回?因为new MPromise()时,发现setTimeout()定时任务就会将其放到异步队列里面,而通过p.then()调用方法时,回调函数中的resolve()并未执行完成,this.state状态一直处于pending状态,自然也就没有调用resolve(onFulfilled())方法

    解决思路:(观察者模式)

    既然 then 自己无法知道 resolve 什么时候执行,是否执行了,那resolve执行完后就需要有个东西告诉then,执行完了。

    即在then里面判断为pending状态时,将成功和失败的方法分别记录到一个数组里面,然后再分别再resolve()和reject()触发时,再去遍历执行数组存进去的函数

    关键代码:

    1. // 设置数组用于存放异步队列中所有的resolve和reject函数
    2. this.onResolveCallback = [];
    3. this.onRejectCallback = [];
    4. // 定义两个处理函数
    5. const resolve = (value) => {
    6. this.value = value;
    7. if (this.state === 'pending') {
    8. this.state = 'fulfilled';
    9. }
    10. if (this.state === 'fulfilled') {
    11. this.onResolveCallback.forEach(resolveCb => resolveCb(this.value));
    12. }
    13. }
    14. const reject = (reason) => {
    15. this.reason = reason;
    16. if (this.state === 'pending') {
    17. this.state = 'rejected';
    18. }
    19. if (this.state === 'rejected') {
    20. this.onRejectCallback.forEach(rejectCb => rejectCb(this.reason));
    21. }
    22. }
    23. .......
    24. // 当异步执行时,状态会一直为pending
    25. if(this.state === 'pending') {
    26. this.onResolveCallback.push(() => {
    27. onFulfilled(this.value)
    28. })
    29. this.onRejectCallback.push(() => {
    30. onRejected(this.reason)
    31. })
    32. }

    完整代码:

    1. class MPromise {
    2. constructor(callback) {
    3. // 定义成功返回参数。为什在构造器里面定义?
    4. this.value = undefined;
    5. // 定义失败返回参数
    6. this.reason = undefined;
    7. // 定义promise的初始状态pending(后面两个状态在执行对应函数后进行更改)
    8. this.state = 'pending';
    9. // 设置数组用于存放异步队列中所有的resolve和reject函数
    10. this.onResolveCallback = [];
    11. this.onRejectCallback = [];
    12. // 定义两个处理函数
    13. const resolve = (value) => {
    14. this.value = value;
    15. if (this.state === 'pending') {
    16. this.state = 'fulfilled';
    17. }
    18. if (this.state === 'fulfilled') {
    19. this.onResolveCallback.forEach(resolveCb => resolveCb(this.value));
    20. }
    21. }
    22. const reject = (reason) => {
    23. this.reason = reason;
    24. if (this.state === 'pending') {
    25. this.state = 'rejected';
    26. }
    27. if (this.state === 'rejected') {
    28. this.onRejectCallback.forEach(rejectCb => rejectCb(this.reason));
    29. }
    30. }
    31. // 执行回调函数
    32. callback(resolve, reject);
    33. }
    34. // then方法时MPromise创建的实例调用的所以在constructor外
    35. // then()方法会接受两个函数参数(onFulfilled和onRejected)
    36. then(onFulfilled, onRejected) {
    37. return new MPromise((resolve, reject) => {
    38. // 容错:onFulfilled,onRejected存在且为function时才能进行调用
    39. let onFulfilledState = onFulfilled ? typeof onFulfilled === 'function' : true; //判断如果onFulfilled传入了则继续判断是否为function函数,否则直接返回true传入什么返回什么
    40. let onRejectedState = onRejected ? typeof onRejected === 'function' : true;
    41. if (onFulfilledState && onRejectedState) {
    42. // 根据对应状态调用不同的处理函数
    43. if (this.state === 'fulfilled') {
    44. resolve(onFulfilled(this.value));
    45. }
    46. if (this.state === 'rejected') {
    47. reject(onRejected(this.value));
    48. }
    49. // 当异步执行时,状态会一直为pending
    50. if (this.state === 'pending') {
    51. // push进去的是下一次resolve函数
    52. this.onResolveCallback.push(()=>onFulfilled(this.value));
    53. this.onRejectCallback.push(()=>onRejected(this.reason));
    54. }
    55. }
    56. });
    57. }
    58. }
    59. // MPromise类调用
    60. let p = new MPromise((resolve, reject) => {
    61. setTimeout(function () {
    62. resolve("success");
    63. // reject("error");
    64. }, 1000)
    65. });
    66. p.then((data) => {
    67. console.log(data);
    68. return data
    69. },err=>{
    70. console.log(err);
    71. }).then((data)=>{
    72. console.log("第二次调用then",data);
    73. })

    3.5实现链式调用

    链式调用的本质是需要调用then方法后返回一个promise对象,且内部仍然会执行resolve和reject函数

    特点:后面每个.then()方法中能获得上一个.then()返回的参数

    解决:push进数组时再通过resolve方法执行就能重新通过then进行调用

    1. // 当异步执行时,状态会一直为pending
    2. if (this.state === 'pending') {
    3. this.onResolveCallback.push(()=>resolve(onFulfilled(this.value)));
    4. this.onRejectCallback.push(()=>resolve(onRejected(this.reason)));
    5. }

    3.6添加静态方法(Promise.resolve,Promise.reject,Promise.all)

    其实就是单独调用new MPromise里面的resolve方法

    1. // 其实就是单独调用new MPromise里面的resolve方法
    2. static resolve = (value) => new MPromise((resolve,reject)=>resolve(value));
    3. static reject = (reason) => new MPromise((resolve,reject)=>resolve(reason));
    4. MPromise.resolve("这是静态方法MPromise.resolve调用").then((data)=>{
    5. console.log(data);
    6. return data;
    7. }).then(data=>{
    8. console.log("第二次调用静态方法MPromise.resolve调用",data);
    9. })
    10. MPromise.reject("这是静态方法MPromise.reject调用").then((error)=>{
    11. console.log(error);
    12. })

    MPromise.all() 关键是需要在循环中调用promise.then()方法向下执行,最后判断数组中所有promise执行完后,通过resolve返回结果

    1. static all = (promiseArr) => new MPromise((resolve, reject)=>{
    2. // 使用数组存放所有MPromise传入的参数数据
    3. let results = [];
    4. // 使用count记录处理的MPromise,每处理一个+1,直到最后一个处理完就返回参数数组
    5. let count = 0;
    6. promiseArr.forEach((promise,index)=>{
    7. promise.then(item=>{
    8. results[index] = item;
    9. count++;
    10. console.log(promise.value);
    11. // 注意此处用数组下标判断会出现问题:setTimeout()异步的会等results其他输出后第二次输出
    12. if(count === promiseArr.length){
    13. resolve(results);
    14. }
    15. });
    16. });
    17. })
    18. let p1 = new MPromise(1);
    19. let p2 = new MPromise((resolve, reject) => {
    20. setTimeout(function(){
    21. resolve("p2");
    22. }, 2000);
    23. })
    24. let p3 = new MPromise((resolve, reject) => {
    25. resolve("p3");
    26. })
    27. let p4 = new MPromise((resolve, reject) => {
    28. resolve("p4");
    29. })
    30. MPromise.all([p1, p2, p3, p4]).then(result => {
    31. console.log(result);
    32. });

    4.问题(实现Promise.all()时为什么不能通过数组循环的index判断if( index+1 === promiseArr.length )所有的promise已执行完成可以返回结果了)

    手写promise中,Promise.all方法实现时,为什么不能使用index进行判断(异步时不会同时打印,等其他打印完再打印异步的)

    使用index判断打印的结果为:p1,p3,p4。p2过一秒后才打印

    1. static all = (promiseArr) => new MPromise((resolve, reject)=>{
    2. // 使用数组存放所有MPromise传入的参数数据
    3. let results = [];
    4. // 使用count记录处理的MPromise,每处理一个+1,直到最后一个处理完就返回参数数组
    5. let count = 0;
    6. promiseArr.forEach((promise,index)=>{
    7. promise.then(item=>{
    8. results[index] = item;
    9. count++;
    10. console.log(promise.value);
    11. // 注意此处用数组下标判断会出现问题:setTimeout()异步的会等results其他输出后第二次输出
    12. if(count === promiseArr.length){
    13. resolve(results);
    14. }
    15. });
    16. });
    17. })

    问题分析:

    promise.then()被调用才能表示当前promise执行完,而index是在外层的,所以用index判断会输出有问题 

    5.完整代码

    1. /*
    2. 实现功能:
    3. 有一个Promise构造函数,传入resolve和reject两个参数,是两个可以执行的函数
    4. promise有三种状态:pending等待,fulfilled成功,rejected失败
    5. 状态pending 一旦转为fulfilled或者rejected,不能再更改
    6. resolve()方法为成功处理方法,将状态由pending转为fulfilled,且传入参数value
    7. reject()方法为失败处理方法,将状态由pending转为rejected,且传入参数reason
    8. then()方法接受两个参数,分别为onFulfilled和onRejected函数,当状态由pending转为fulfilled后执行onFulfilled函数,由pending转为rejected后指向onRejected函数
    9. .then()方法支持链式调用,创建Promise实例后,可以通过实例一直调用.then()方法触发
    10. 静态方法的实现:Promise.resolve(),Promise.reject(),Promise.all()
    11. 基本步骤:
    12. 需要创建一个Promise类,并且添加一个回调方法 callback,作为Promise 的参数
    13. callback接收resolve 和 reject 作为参数
    14. 定义promise的三种状态,实现then方法
    15. then()方法可实现异步操作(用定时器进行测试)
    16. 实现链式调用
    17. 添加静态方法
    18. */
    19. // 问题:写在constructor里面的函数和写在constructor外的函数区别
    20. // constructor里面的函数,通过构造方法创建时就必须传入回调函数
    21. class MPromise {
    22. constructor(callback) {
    23. // 定义成功返回参数。为什在构造器里面定义?
    24. this.value = undefined;
    25. // 定义失败返回参数
    26. this.reason = undefined;
    27. // 定义promise的初始状态pending(后面两个状态在执行对应函数后进行更改)
    28. this.state = 'pending';
    29. // 设置数组用于存放异步队列中所有的resolve和reject函数
    30. this.onResolveCallback = [];
    31. this.onRejectCallback = [];
    32. // 定义两个处理函数
    33. const resolve = (value) => {
    34. this.value = value;
    35. if (this.state === 'pending') {
    36. this.state = 'fulfilled';
    37. }
    38. if (this.state === 'fulfilled') {
    39. this.onResolveCallback.forEach(resolveCb => resolveCb(this.value));
    40. }
    41. }
    42. const reject = (reason) => {
    43. this.reason = reason;
    44. if (this.state === 'pending') {
    45. this.state = 'rejected';
    46. }
    47. if (this.state === 'rejected') {
    48. this.onRejectCallback.forEach(rejectCb => rejectCb(this.reason));
    49. }
    50. }
    51. // 执行回调函数(对传入非function的进行处理)
    52. typeof callback === 'function'? callback(resolve, reject): resolve(callback);
    53. }
    54. // then方法时MPromise创建的实例调用的所以在constructor外
    55. // then()方法会接受两个函数参数(onFulfilled和onRejected)
    56. then(onFulfilled, onRejected) {
    57. return new MPromise((resolve, reject) => {
    58. // 容错:onFulfilled,onRejected存在且为function时才能进行调用
    59. let onFulfilledState = onFulfilled ? typeof onFulfilled === 'function' : true; //判断如果onFulfilled传入了则继续判断是否为function函数,否则直接返回true传入什么返回什么
    60. let onRejectedState = onRejected ? typeof onRejected === 'function' : true;
    61. if (onFulfilledState && onRejectedState) {
    62. // 根据对应状态调用不同的处理函数
    63. if (this.state === 'fulfilled') {
    64. resolve(onFulfilled(this.value));
    65. }
    66. if (this.state === 'rejected') {
    67. reject(onRejected(this.value));
    68. }
    69. // 当异步执行时,状态会一直为pending
    70. if (this.state === 'pending') {
    71. // push进去的是下一次resolve函数
    72. this.onResolveCallback.push(() => resolve(onFulfilled(this.value)));
    73. this.onRejectCallback.push(() => resolve(onRejected(this.reason)));
    74. }
    75. }
    76. });
    77. }
    78. // 其实就是单独调用new MPromise里面的resolve方法
    79. static resolve = (value) => new MPromise((resolve, reject) => resolve(value));
    80. static reject = (reason) => new MPromise((resolve, reject) => resolve(reason));
    81. // 关键是需要在循环中调用promise.then()方法向下执行,最后判断数组中所有promise执行完后,通过resolve返回结果
    82. static all = (promiseArr) => new MPromise((resolve, reject)=>{
    83. // 使用数组存放所有MPromise传入的参数数据
    84. let results = [];
    85. // 使用count记录处理的MPromise,每处理一个+1,直到最后一个处理完就返回参数数组
    86. let count = 0;
    87. promiseArr.forEach((promise,index)=>{
    88. promise.then(item=>{
    89. results[index] = item;
    90. count++;
    91. console.log(promise.value);
    92. // 注意此处用数组下标判断会出现问题:setTimeout()异步的会等results其他输出后第二次输出
    93. if(count === promiseArr.length){
    94. resolve(results);
    95. }
    96. });
    97. });
    98. })
    99. }
    100. // // MPromise类调用
    101. // let p = new MPromise((resolve, reject) => {
    102. // setTimeout(function () {
    103. // resolve("success");
    104. // // reject("error");
    105. // }, 1000)
    106. // });
    107. // p.then((data) => {
    108. // console.log(data);
    109. // return data
    110. // },err=>{
    111. // console.log(err);
    112. // }).then((data)=>{
    113. // console.log("第二次调用then",data);
    114. // })
    115. // MPromise.resolve("这是静态方法MPromise.resolve调用").then((data)=>{
    116. // console.log(data);
    117. // return data;
    118. // }).then(data=>{
    119. // console.log("第二次调用静态方法MPromise.resolve调用",data);
    120. // })
    121. // MPromise.reject("这是静态方法MPromise.reject调用").then((error)=>{
    122. // console.log(error);
    123. // })
    124. let p1 = new MPromise(1);
    125. let p2 = new MPromise((resolve, reject) => {
    126. setTimeout(function(){
    127. resolve("p2");
    128. }, 2000);
    129. })
    130. let p3 = new MPromise((resolve, reject) => {
    131. resolve("p3");
    132. })
    133. let p4 = new MPromise((resolve, reject) => {
    134. resolve("p4");
    135. })
    136. MPromise.all([p1, p2, p3, p4]).then(result => {
    137. console.log(result);
    138. });
    139. // // Promise类调用
    140. // let p = new Promise((resolve, reject) => {
    141. // // 执行resolve或者reject函数,并传入参数
    142. // setTimeout(function (){
    143. // resolve("success");
    144. // },1000)
    145. // });
    146. // p.then((data) => {
    147. // console.log(data);
    148. // })

  • 相关阅读:
    分布式解决方案 Percolator--详解
    JavaScript学习总结
    【面试题精讲】Java成员变量与局部变量的区别?
    MySQL函数count
    国网云(华为组件)使用
    Docker出现容器名称重复如何解决
    Fix Xcode14 bundle need sign
    前后端分离项目,vue+uni-app+php+mysql在线小说电子书阅读小程序系统 开题报告
    以 Golang 为例详解 AST 抽象语法树
    浅谈城市综合管廊分类及其运维管理-Susie 周
  • 原文地址:https://blog.csdn.net/qq_34569497/article/details/133906250