JS基础 Promise

2022-10-31 13:38:11

Promise

JavaScript 中存在很多异步操作,Promise 将异步操作队列化,按照期望的顺序执行,返回符合预期的结果。可以通过链式调用多个 Promise 达到我们的目的。

Promise 在各种开源库中已经实现,现在标准化后被浏览器默认支持。

Promise 是一个拥有 then 方法的对象或函数。

问题探讨

下面通过多个示例来感受一下不使用 promise 时,处理相应问题的不易,及生成了不便阅读的代码。

定时嵌套

下面是一个定时器执行结束后,执行另一个定时器,这种嵌套造成代码不易阅读

在这里插入图片描述

<!DOCTYPE html><html><head><meta charset="utf-8"><title>wgchen</title></head><style>
  div{
    width:100px;
    height:100px;
    background: yellowgreen;
    position: absolute;}</style><body><div></div></body><script>functioninterval(callback, delay=100){let id=setInterval(()=>callback(id), delay);}const div= document.querySelector("div");interval(timeId=>{const left=parseInt(window.getComputedStyle(div).left);
    div.style.left= left+10+"px";if(left>200){clearInterval(timeId);interval(timeId=>{const width=parseInt(window.getComputedStyle(div).width);
        div.style.width= width-1+"px";if(width<=0)clearInterval(timeId);},10);}},100);</script></html>

图片加载

下面是图片后设置图片边框,也需要使用回调函数处理,代码嵌套较复杂

在这里插入图片描述

functionloadImage(file, resolve, reject){const image=newImage();
  image.src= file;
  image.onload=()=>{resolve(image);};
  image.onerror=()=>{reject(newError("load fail"));};
  document.body.appendChild(image);}loadImage("888.png",image=>{
    image.style.border="solid 5px red";},error=>{
    console.log(error);});

加载文件

下面是异步加载外部JS文件,需要使用回调函数执行,并设置的错误处理的回调函数

在这里插入图片描述

<!DOCTYPE html><html><head><meta charset="utf-8"><title>wgchen</title><link rel="shortcut icon" href="#"/></head><body></body><script>functionload(file, resolve, reject){const script= document.createElement("script");
  script.src= file;
  script.onload= resolve;
  script.onerror= reject;
  document.body.appendChild(script);}load("hd.js",script=>{
    console.log(`${script.path[0].src} 加载成功`);hd();},error=>{
    console.log(`${error.srcElement.src} 加载失败`);});</script></html>

hd.js

functionhd(){
  console.log("hd function run");}

如果要加载多个脚本时需要嵌套使用,下面 wgchen.js 依赖 hd.js,需要先加载 hd.js 后加载wgchen.js

不断的回调函数操作将产生回调地狱,使代码很难维护

wgchen.js

functionwgchen(){
    console.log("wgchen function run");hd();}

在这里插入图片描述

<!DOCTYPE html><html><head><meta charset="utf-8"><title>wgchen</title><link rel="shortcut icon" href="#"/></head><body></body><script>functionload(file, resolve, reject){const script= document.createElement("script");
  script.src= file;
  script.onload= resolve;
  script.onerror= reject;
  document.body.appendChild(script);}load("hd.js",script=>{load("wgchen.js",script=>{wgchen();},error=>{
        console.log(`${error.srcElement.src} 加载失败`);});},error=>{
    console.log(`${error.srcElement.src} 加载失败`);});</script></html>

异步请求

使用传统的异步请求也会产生回调嵌套的问题,下在是获取wgchen的成绩,需要经过以下两步

1、根据用户名取得 wgchen 的编号
2、根据编号获取成绩

在这里插入图片描述

启动PHP服务

<!DOCTYPE html><html><head><meta charset="utf-8"><title>wgchen</title><link rel="shortcut icon" href="#"/></head><body></body><script>functionajax(url, resolve, reject){let xhr=newXMLHttpRequest();
  xhr.open("GET", url);
  xhr.send();
  xhr.onload=function(){if(this.status==200){resolve(JSON.parse(this.response));}else{reject(this);}};}ajax("http://tt.cc/testData/user.php?name=wgchen",user=>{// console.log(user.id);ajax(`http://tt.cc/testData/wgchen.php?id=${user["id"]}`,response=>{
      console.log(response);});});</script></html>

user.php

<?php

$user=['name'=>$_GET['name'],'file'=>'user.php','id'=>18];

echojson_encode($user);

wgchen.php

<?php

$user=['name'=>'wgchen','file'=>'wgchen.php','id'=>$_GET['id']];

echojson_encode($user);

肯德基

下面是模拟肯德基吃饭的事情,使用 promise 操作异步的方式每个阶段会很清楚
在这里插入图片描述

let kfc=newPromise((resolve, reject)=>{
  console.log("肯德基厨房开始做饭");resolve("我是肯德基,你的餐已经做好了");});let dad= kfc.then(msg=>{
  console.log(`收到肯德基消息:${msg}`);return{then(resolve){setTimeout(()=>{resolve("孩子,我吃了两秒了,不辣,你可以吃了");},2000);}};});let son= dad.then(msg=>{returnnewPromise((resolve, reject)=>{
    console.log(`收到爸爸消息:${msg}`);setTimeout(()=>{resolve("妈妈,我和wgchen爸爸吃完饭了");},2000);});});let ma= son.then(msg=>{
  console.log(`收到孩子消息:${msg},事情结束`);});

而使用以往的回调方式,就会让人苦不堪言
在这里插入图片描述

functionnotice(msg, then){then(msg);}functionmeal(){notice("肯德基厨房开始做饭",msg=>{
    console.log(msg);notice("我是肯德基,你的餐已经做好",msg=>{
      console.log(`收到肯德基消息:${msg}`);setTimeout(()=>{notice("孩子,我吃了两秒了,不辣,你可以吃了",msg=>{
          console.log(`收到爸爸消息:${msg}`);setTimeout(()=>{notice("妈妈,我和wgchen吃完饭了",msg=>{
              console.log(`收到孩子消息:${msg},事情结束`);});},2000);});},2000);});});}meal();

异步状态

Promise 可以理解为承诺,就像我们去KFC点餐服务员给我们领取餐票,这就是承诺。如果餐做好了叫我们这就是成功,如果没有办法给我们做出食物这就是拒绝。

  • 一个 promise 必须有一个 then 方法用于处理状态改变

状态说明

Promise 包含 pending、fulfilled、rejected 三种状态

  • pending 指初始等待状态,初始化 promise 时的状态
  • resolve 指已经解决,将 promise 状态设置为 fulfilled
  • reject 指拒绝处理,将 promise 状态设置为 rejected
  • promise 是生产者,通过 resolve 与 reject 函数告之结果
  • promise 非常适合需要一定执行时间的异步任务
  • 状态一旦改变将不可更改

promise 是队列状态,就像体育中的接力赛,或多米诺骨牌游戏,状态一直向后传递,当然其中的任何一个promise也可以改变状态。

在这里插入图片描述

promise 没有使用 resolve 或 reject 更改状态时,状态为 pending

console.log(newPromise((resolve, reject)=>{}));

在这里插入图片描述

当更改状态后

console.log(newPromise((resolve, reject)=>{resolve("fulfilled");}));

console.log(newPromise((resolve, reject)=>{reject("rejected");}));

在这里插入图片描述
promise 创建时即立即执行即同步任务,then 会放在异步微任务中执行,需要等同步任务执行后才执行。

let promise=newPromise((resolve, reject)=>{resolve("fulfilled");
  console.log("wgchen");});

promise.then(msg=>{
  console.log(msg);});

console.log("wgchen.blog.csdn.net");

在这里插入图片描述

  • promise 的 then、catch、finally的方法都是异步任务
  • 程序需要将主任务执行完成才会执行异步队列任务

在这里插入图片描述

const promise=newPromise(resolve=>resolve("success"));

promise.then(alert);alert("wgchen.blog.csdn.net");

promise.then(()=>{alert("wgchen");});

Promise 状态设置为 fulfilled ,然后执行 then 方法

下例在三秒后将 Promise 状态设置为 fulfilled ,然后执行 then 方法

newPromise((resolve, reject)=>{setTimeout(()=>{resolve("fulfilled");},3000);}).then(msg=>{
    console.log(msg);},error=>{
    console.log(error);});

状态被改变后就不能再修改了,下面先通过 resolve 改变为成功状态,表示 promise 状态已经完成,就不能使用 reject 更改状态了

在这里插入图片描述

newPromise((resolve, reject)=>{resolve("操作成功");reject(newError("请求失败"));}).then(msg=>{
    console.log(msg);},error=>{
    console.log(error);});

动态改变

下例中 p2 返回了 p1 所以此时 p2 的状态已经无意义了,后面的 then 是对 p1 状态的处理。

const p1=newPromise((resolve, reject)=>{
  • 作者:知其黑、受其白
  • 原文链接:https://wgchen.blog.csdn.net/article/details/122821325
    更新时间:2022-10-31 13:38:11