ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Promise的构造函数方法

2021-04-30 12:34:13  阅读:173  来源: 互联网

标签:resolve console log Promise reject const 方法 构造函数


Promise是什么:
1、认识Promise:
Promise 是异步操作的一种解决方案。
先给大家讲一下什么是异步:
回调函数其实就是异步操作,例:

      document.addEventListener(
        'click',
        () => {
          console.log('这里是异步的');
        },
        false
      );
      console.log('这里是同步的');

2、什么时候使用 Promise:
Promise 一般用来解决层层嵌套的回调函数(回调地狱 callback hell)的问题。

在这里插入代码片

Promise的基本用法:
1、实例化构造函数生成实例对象:
Promise 解决的不是回调函数,而是回调地狱,即并不是用了Promise就用不了回调函数,它们两个是可以共存的。

// 实例化构造函数生成实例对象:
const p = new Promise(() => {});

2、Promise 的状态:
Promise的状态解决了Promise的一系列行为。Promise 有 3 种状态,一开始是 pending(未完成),执行 resolve,变成 fulfilled(resolved),已成功;执行 reject,变成 rejected,已失败;Promise 的状态一旦变化,就不会再改变了。

一开始是 pending(未完成):

      const p = new Promise((resolve, reject) => {

      });
      console.log(p); // Promise {<pending>

执行 resolve,变成 fulfilled(resolved),已成功:

      const p = new Promise((resolve, reject) => {
        resolve();
	  });
      console.log(p); // Promise {<fulfilled>: undefined}

执行 reject,变成 rejected,已失败:

      const p = new Promise((resolve, reject) => {
        reject();
      });
      console.log(p); // Promise {<rejected>: undefined}

但这里请大家注意:Promise里面第一个参数是成功状态的回调函数,第二个参数是失败状态的回调函数,Promise里面的resolve和reject只是形参(名字可以随便写,想起什么名就起什么名),写成resolve和reject的原因是为了语义化更强一些,那么,请问下面代码执行结果是什么:

          const p = new Promise((r1,r2) => {
            r2();
          });
          console.log(p);

因为r1 和 r2 只是形参,第二个参数是失败状态的回调函数,所以调用 r2 就等同于调用 失败状态的回调函数 所以毫无疑问结果是Promise {<rejected>: undefined},在这里只是给大家提个醒,大家不要弄迷糊了。

Promise 的状态一旦变化,就不会再改变了:

      const p = new Promise((resolve, reject) => {
        resolve();
        reject();
      });
      console.log(p); // Promise {<fulfilled>: undefined}

3、then方法(简单说明一下,具体在后面讲):
这里then传两个函数,成功了用第一个函数,失败了用第二个函数。

// 失败:
      const p = new Promise((resolve, reject) => {   
        reject();
      });

      p.then(
        () => {
          console.log('success');
        },
        () => {
          console.log('error');
        }
      ); 
      // error
// 成功:
      const p = new Promise((resolve, reject) => {   
        resolve();
      });

      p.then(
        () => {
          console.log('success');
        },
        () => {
          console.log('error');
        }
      ); 
      // success

4、resolve 和 reject 函数的参数:
resolve 和 reject 函数的参数都会传给相应的then方法里面函数的形参,即resolve()传它的参数给then里面第一个函数的形参,reject()传它的参数给then里面第二个函数的形参;举例:

// 成功的时候:
      const p = new Promise((resolve, reject) => {   
        resolve({username:'Alex'});
      });
      p.then(
        data => {
          console.log('success', data);
        },
        err => {
          console.log('error', err);
        }
      );
		// success {username: "alex"}
// 失败的时候:
      const p = new Promise((resolve, reject) => {   
        reject(new Error('reason'));
      });
      p.then(
        data => {
          console.log('success', data);
        },
        err => {
          console.log('error', err);
        }
      );
		// error Error: reason
    //		at 2-2.Promise 的基本用法.html:28
    //		at new Promise (<anonymous>)
    //		at 2-2.Promise 的基本用法.html:16

then方法:
1、什么时候执行:
pending->fulfilled 时,执行 then 的第一个回调函数
pending->rejected 时,执行 then 的第二个回调函数
2、执行后的返回值:
then 方法执行后返回一个新的 Promise 对象。

      const p = new Promise((resolve, reject) => {
        resolve();
        // reject();
      });
      const p2 = p
        .then(
          () => {},
          () => {}
        )
        .then() // 因为then方法返回的是一个promise,所以可以在后面再添加then方法。
        .then();
	  console.log(p, p2, p === p2); // Promise {<fulfilled>: undefined} Promise {<pending>} false

3、then 方法返回的 Promise 对象的状态改变:
在前面讲过第一个new 的promise可以决定紧挨着后面then的执行回调函数,例:

      const p = new Promise((resolve, reject) => {
        reject();
      });
      p.then(
        () => {
          console.log('success');
        },
        () => {
          console.log('err');
        });
        // err

因为在p中执行reject(),所以执行p紧挨着的then的第二个回调函数,因此输出err,
而我们都知道then方法可以继续使用在上一个then方法的后面的,但是大家有没有想过新的then方法是怎么执行的呢?下面进行讲解:
在讲解之前大家先判断一下下面这块代码的打印出来的值是多少?

// 案例1:
      const p = new Promise((resolve, reject) => {
        reject();
      });
      p.then(
        () => {
          console.log('success');
        },
        () => {
          console.log('err');
        }).then(
          data => {
            console.log('success2', data);
          },
          err => {
            console.log('err2', err);
          }
        )

这个值是err success2 undefined,
我先给大家分析一下,在p中执行reject(),所以在第一个then中执行第二个回调函数,所以打印出err,然后在第一个then中默认返回的永远都是成功状态的 Promise 对象,所以在第二个then中调用第第一个回调函数,所以接着打印出success2 undefined,由此可见后面的then执行第一个回调函数还是第二个回调函数看的是前面的then,可能大家对
在第一个then中默认返回的永远都是成功状态的 Promise 对象
这句话不太理解 ,下面我通过代码给大家演示:
先简单通过代码看一下:

//          在 then 的回调函数中,return 后面的东西,会用 Promise 包装一下
          return undefined;
//          等价于
          return new Promise(resolve => {
            resolve(undefined);
          });

这是详细讲解:
1、在所有函数中都有return值,没有写的时候就默认返回undefined,所以在第一个then里面就默认返回undefined(相当于程序中默认有 return undefined; 这样一行代码)

        () => {
          console.log('err');
          // 默认这里有 return undefined;这样一行代码
        })

又因为 默认返回的永远都是成功状态的 Promise 对象,即:

        () => {
          console.log('err');
          // 默认这里有 return undefined;这样一行代码
 // 因为默认返回的永远都是成功状态的 Promise 对象,所以相当于一个新的Promise里面执行resolve(),即:
          return new Promise((resolve, reject) => {
            resolve(undefined); // 因为默认返回undefined,所以resolve里面参数是undefined
        })

因为上一个then执行resolve,所以到第二个then那里就执行第一个回调函数,所以打印出 success2 undefined,打印出undefined是因为在一个then里面的reject传进去的undefined。讲到这里大家可能会问:默认返回的永远都是成功状态的 Promise 对象,那么如何返回失败状态的Promise对象呢?其实是这样的,then里面默认的是返回的永远都是成功状态的 Promise 对象,那么我直接给一个失败状态的Promise,那么不就不会再出现默认值了呢,没错,就是这样。举例:

      const p = new Promise((resolve, reject) => {
        reject();
      });
      p.then(
        () => {
          console.log('success');
        },
        () => {
          console.log('err');
/          
          return new Promise((resolve, reject) => {
            reject('reason');
           });
/          
        }).then(
          data => {
            console.log('success2', data);
          },
          err => {
            console.log('err2', err);
          }
        )

大家注意横线里面的两行代码,那样写即程序不会再执行那个 默认的正确状态的Promis对象了,而执行自己写的那个错误的Promise对象(即/中间的代码),所以,这个案例的执行结果是:err err2 reason,原理同案例1一样。

那么简单测试一下上面知识是否掌握了,上案例:

      const p = new Promise((resolve, reject) => {
        reject();
      });
      p.then(
        () => {
          console.log('success');
        },
        () => {
// 步骤一:
          console.log('err');
        }).then(
          data => {
// 步骤二:
            console.log('success2', data);
          },
          err => {
            console.log('err2', err);
          }
        ).then(
          data => {
// 步骤三:
            console.log('success3', data);
          },
          err => {
            console.log('err3', err);
          }
        );

只要大家将上面知识理解了,那么这个案例就是小菜一碟,答案是:err success2 undefined success3 undefined,执行的分别是步骤一,步骤二,步骤三。
catch方法:
1、有什么用:
在前面的then方法中,我们知道它里面有两个回调函数(第一个处理成功的状态,第二个处理失败的状态),但在实际开发中一般then只处理成功的状态,因此只传一个回调函数,因此catch就是用来专门处理失败的状态的,即catch 本质上是 then 的特例,就是then(null, err => {});
2、基本用法:

      new Promise((resolve, reject) => {
        // resolve(123);
        reject('reason');
      }).then(data => {
        console.log(data); // then 处理正确的状态
      }).catch(err => {
        console.log(err); // catch 处理错误的状态
      })
      // reason

// 上面的catch其实就相当于
        .then(null, err => {
          console.log(err);
        });

catch() 可以捕获它前面的错误,一般总是建议,Promise 对象后面要跟 catch 方法,这样可以处理 Promise 内部发生的错误:
catch可以捕获前面的错误,如果错误一旦被catc捕获到则错误就消失了。还有就是catch默认也是返回一个成功状态的Promise对象(原因很简单,catch本质是then,因为then默认返回成功状态的Promise对象,所以catch也是返回成功状态的Promise对象),所以catch后面跟的then只会执行成功的回调函数,如果想执行失败状态的回调函数需要自己手动return 失败状态的Promise对象,除了这种方法外还有一种方法,见代码:

      new Promise((resolve, reject) => {
        // resolve(123);
        reject('reason');
      })
        .then(data => {
          console.log(data);
        }) /// 第一块
        .catch(err => {
          console.log(err);
          throw new Error('reason');
        }) 
        .then(data => {
          console.log(data);
        })  第二块
        .catch(err => {
          console.log(err);
        }); /
		// reason
		// Error: reason

reason是第一块代码执行的结果, Error: reason是第二块代码执行的结果。在第一块代码里扔一个错误,那么就会被第二块代码中的catch捕获到,这样也不会再执行then里面的成功状态的回调函数了。
Promise.resolve() 和 Promise.reject():
1、Promise.resolve():
是成功状态 Promise 的一种简写形式。

      new Promise(resolve => resolve('foo'));
      // 这个地方的resolve是一个形参,名字想怎么写就怎么写
      // 简写
      Promise.resolve('foo'); 
      // 这里的resolve是一个固定的方法名,不能乱写

参数:
(1)一般参数(最应该关注):

      Promise.resolve('foo').then(data => {
        console.log(data);
      });  // foo

(2)特殊参数(简单了解一下即可,不要深究):
1、把Promise当作参数传进去。

        const p1 = new Promise(resolve => {
        setTimeout(resolve, 1000, '我执行了');
      });
      Promise.resolve(p1).then(data => {
        console.log(data);
      }); // 我执行了(注:在一秒后打印)

这是为什么呢?原因是:当 Promise.resolve() 接收的是 Promise 对象时,直接返回这个 Promise 对象,什么都不做。
即上面的代码等同于:

      const p1 = new Promise(resolve => {
        setTimeout(resolve, 1000, '我执行了');
// 上面的setTimeout等同于:
        // setTimeout(() => {
        //   resolve('我执行了');
        // }, 1000);
      });
      p1.then(data => {
        console.log(data);
      }); // 我执行了(注:一秒后打印)
      console.log(Promise.resolve(p1) === p1); // true

还有就是,当 resolve 函数接收的是 Promise 对象时,后面的 then 会根据传递的 Promise 对象的状态变化决定执行哪一个回调。
上代码进行描述:

      const p1 = new Promise(resolve => {
        setTimeout(resolve, 1000, '我执行了');
      });
      new Promise(resolve => resolve(p1)).then(data => {
        console.log(data);
      });

上面那句话的意思就是如果函数接收的是一个Promise对象(即上面代码的p1)时,后面的then受p1支配,因为p1在一秒后执行了resolve('我执行了');所以就给then里面传了个 ‘我执行了’ ,所以then执行后打印出 我执行了。

2、具有 then 方法的对象:
因这种形式在实际开发中不咋用,这里不再细讲,大家知道有这个东西就行。(要是碰到了直接查文档就完事了)

2、Promise.reject():
失败状态 Promise 的一种简写形式。

      new Promise((resolve, reject) => {
        reject('reason');
      });
      // 等价于
      Promise.reject('reason');

参数:
不管什么参数,都会原封不动地向后传递,作为后续方法的参数。(跟resolve相比简单多了)

还有一个Promise.resolve() 和 Promise.reject()的用处就是用在then方法的return中,如:

      new Promise((resolve, rejcet) => {
        resolve(123);
      })
        .then(data => {
          // return data;
          // return Promise.resolve(data); // 传失败状态的Promise对象的简写
          return Promise.reject('reason'); // 传失败状态的Promise对象的简写
        })
        .then(data => {
          console.log(data);
        })
        .catch(err => console.log(err));
        // reason

Promise.all():
1、有什么用:
Promise.all() 关注多个 Promise 对象的状态变化;可以在Promise对象中传入多个 Promise 实例,包装成一个新的 Promise 实例返回。
2、基本用法:
Promise.all() 的状态变化与所有传入的 Promise 实例对象状态有关
所有状态都变成 resolved,最终的状态才会变成 resolved
只要有一个变成 rejected,最终的状态就变成 rejected
见代码:

// 封装一个延迟函数:
      const delay = ms => {
        return new Promise(resolve => {
          setTimeout(resolve, ms);
        });
      };

      const p1 = delay(1000).then(() => {
        console.log('p1 完成了');
        return 'p1'; // 默认返回成功状态的Promise对象
      });
      const p2 = delay(2000).then(() => {
        console.log('p2 完成了');
        return 'p2'; // 默认返回成功状态的Promise对象
      });
      
      const p = Promise.all([p1, p2]);
      
      p.then(
        data => {
          console.log(data);
        },
        err => {
          console.log(err);
        }
      );

上面代码中的执行结果是:p1完成了(一秒后),p2完成了 (2) [“p1”, “p2”] (两秒后)
这块代码是最终的状态是 resolved
再看下面的代码:

      const delay = ms => {
        return new Promise(resolve => {
          setTimeout(resolve, ms);
        });
      };

      const p1 = delay(1000).then(() => {
        console.log('p1 完成了');
        return Promise.reject('reason');
      });
      const p2 = delay(2000).then(() => {
        console.log('p2 完成了');
        return 'p2';
      });
      
      const p = Promise.all([p1, p2]);
      
      p.then(
        data => {
          console.log(data);
        },
        err => {
          console.log(err);
        }
      );

这块代码的结果是:p1完成了 reason (注:一秒后打印) p2完成了 (注:两秒后打印)
这块代码中有rejected,所以最终状态就是rejected,可能大家疑惑为什么reason在 p1完成了 后面出现,大家可以这样理解:因为系统检测到某个地方出现了rejected,所以直接判定Promise.all的状态是rejected,所以直接执行p后面then方法的第二个回调函数,所以打印出reason,又因为那个rejected的状态是在p1中检测到的,所以reason出现在 p1完成了 的后面。
大家可以通过下面的例子检测字迹是否理解:

      const delay = ms => {
        return new Promise(resolve => {
          setTimeout(resolve, ms);
        });
      };

      const p1 = delay(1000).then(() => {
        console.log('p1 完成了');
        return 'p1';
      });
      const p2 = delay(2000).then(() => {
        console.log('p2 完成了');
        return Promise.reject('reason');
      });
      
      const p = Promise.all([p1, p2]);
      
      p.then(
        data => {
          console.log(data);
        },
        err => {
          console.log(err);
        }
      );

这里的结果是:p1完成了(注:一秒后打印出来) p2完成了 reason(注:两秒后打印出来)
Promise.race() 和 Promise.allSettled():
先声明一下,这两个方法大家简单了解一下即可。
1、Promise.race():
Promise.race() 的状态取决于第一个完成的 Promise 实例对象,如果第一个完成的成功了,那最终的就成功;如果第一个完成的失败了,那最终的就失败。

      const delay = ms => {
        return new Promise(resolve => {
          setTimeout(resolve, ms);
        });
      };
      const p1 = delay(1000).then(() => {
        console.log('p1 完成了');
        return 'p1';
      });
      const p2 = delay(2000).then(() => {
        console.log('p2 完成了');
        return 'p2';
      });
      const racePromise = Promise.race([p1, p2]);
      racePromise.then(
        data => {
          console.log(data);
        },
        err => {
          console.log(err);
        }
      );
      const delay = ms => {
        return new Promise(resolve => {
          setTimeout(resolve, ms);
        });
      };
      const p1 = delay(1000).then(() => {
        console.log('p1 完成了');
        return 'p1';
      });
      const p2 = delay(2000).then(() => {
        console.log('p2 完成了');
        return Promise.reject('reason');
      });
      const racePromise = Promise.race([p1, p2]);
      racePromise.then(
        data => {
          console.log(data);
        },
        err => {
          console.log(err);
        }
      );

这里提供两个例子,供大家自己自行下去进行验证学习,这里就不细讲了,大家在自己编译器上一运行就一目了然了。
2、Promise.allSettled():
Promise.allSettled() 的状态与传入的Promise 状态无关,它后面的then方法永远执行成功的回调函数,它只会忠实的记录下各个 Promise 的表现。见代码:

      const delay = ms => {
        return new Promise(resolve => {
          setTimeout(resolve, ms);
        });
      };
      
      const p1 = delay(1000).then(() => {
        console.log('p1 完成了');
        return 'p1';
      });
      const p2 = delay(2000).then(() => {
        console.log('p2 完成了');
        return Promise.reject('reason');
      });
      
      const allSettledPromise = Promise.allSettled([p1, p2]);
      allSettledPromise.then(data => {
        console.log('succ', data);
      });
      const delay = ms => {
        return new Promise(resolve => {
          setTimeout(resolve, ms);
        });
      };
      const p1 = delay(1000).then(() => {
        console.log('p1 完成了');
        return Promise.reject('reason');
      });
      const p2 = delay(2000).then(() => {
        console.log('p2 完成了');
        return Promise.reject('reason');
      });
      const allSettledPromise = Promise.allSettled([p1, p2]);
      allSettledPromise.then(data => {
        console.log('succ', data);
      });

上面两个例子大家自行演示,看到结果大家都会明白的。
Promise的注意事项:
1、resolve 或 reject 函数执行后的代码:
推荐在调用 resolve 或 reject 函数的时候加上 return,不再执行它们后面的代码。
如:

      new Promise((resolve, reject) => {
      //   // return resolve(123);
        return reject('reason');
      });

虽然 resolve 或 reject 函数的后面的代码仍可以执行。如:

      new Promise((resolve, reject) => {
      //   // return resolve(123);
        return reject('reason');
        console.log('hi');
      }); // hi

但是不建议这样写。
2、Promise.all/race/allSettled 的参数问题:
参数如果不是 Promise对象 的数组,系统会默认的将不是 Promise 的数组元素转变成 Promise对象 的数组。

      Promise.all([1, 2, 3]).then(datas => {
        console.log(datas);
      });
      // 等价于
      Promise.all([
        Promise.resolve(1),
        Promise.resolve(2),
        Promise.resolve(3)
      ]).then(datas => {
        console.log(datas);
      });

参数不只是数组,任何可遍历的都可以作为参数:
如:原生可遍历的:数组、字符串、Set、Map、NodeList、arguments
和非原生可遍历的(通过Iterate)
举个栗子:

// Set作为参数
      Promise.all(new Set([1, 2, 3])).then(datas => {
        console.log(datas);
      });

3、Promise.all/race/allSettled 的错误处理:
单独处理:

// 第一个案例:
      const delay = ms => {
        return new Promise(resolve => {
          setTimeout(resolve, ms);
        });
      };

      const p1 = delay(1000).then(() => {
        console.log('p1 完成了');
        return Promise.reject('reason');
      }).catch(err => {
        console.log('p1', err);
      });
      const p2 = delay(2000).then(() => {
        console.log('p2 完成了');
        return Promise.reject('reason');
      }).catch(err => {
         console.log('p2', err);
      });

      const allPromise = Promise.all([p1, p2]);
      allPromise.then(datas => {
          console.log(datas);
        });

统一处理:

// 第二个案例:
      const delay = ms => {
        return new Promise(resolve => {
          setTimeout(resolve, ms);
        });
      };

      const p1 = delay(1000).then(() => {
        console.log('p1 完成了');
        return Promise.reject('reason');
      });

      const p2 = delay(2000).then(() => {
        console.log('p2 完成了');
        return Promise.reject('reason');
      });

      const allPromise = Promise.all([p1, p2]);
      allPromise.then(datas => {
          console.log(datas);
        }).catch(err => console.log(err));
  错误既可以单独处理,也可以统一处理
  一旦被处理,就不会在其他地方再处理一遍(上面第二个案例)

标签:resolve,console,log,Promise,reject,const,方法,构造函数
来源: https://blog.csdn.net/qq_52207728/article/details/116240791

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有