【ES6】Promise 使用

news/2024/7/10 23:01:55 标签: es6, javascript, 前端

文章目录

  • 一、含义
    • 1、是什么
    • 2、特点
  • 二、用法
    • 1、基本使用
      • 示例:timeout
      • 示例:异步加载图片
    • 2、resolve函数和reject函数带有参数
      • 2.1 resolve
        • 2.1.1 参数为正常值的情况
        • 2.1.2 参数为Promise 实例的情况
      • 2.2reject
    • 3、Promise.prototype.then()
    • 4、Promise.prototype.catch()
    • 5、Promise.prototype.finally()
    • 6、Promise.all()
    • 7、Promise.resolve()
    • 8、Promise.reject()
  • 三、练习题
    • 1、第1题
    • 2、第2题
    • 3、第3题
    • 4、第4题
    • 5、第5题

一、含义

1、是什么

Promise 是异步编程的一种解决方案

2、特点

Promise对象有以下两个特点:
1、对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)
2、一旦状态改变,就不会再变,任何时候都可以得到这个结果

二、用法

1、基本使用

ES6 规定,Promise对象是一个构造函数,用来生成Promise实例
代码示例:

const promise = new Promise(function (resolve, reject) {
  // ... some code
  console.log('这里的代码是同步代码,会立即执行~');

  let flag = true;
  // let flag = false;
  if (flag) {
    resolve(true);
  } else {
    reject(false);
  }
});

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数:

promise.then(
  function (value) {
  	// success
  	// Promise对象的状态变为resolved时调用
  },
  function (error) {
    // failure
    // Promise对象的状态变为rejected时调用
  }
);

示例:timeout

function timeout(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('done');
    }, time);
  });
}

timeout(2000).then((value) => {
  console.log(value);
});

示例:异步加载图片

function loadImageAsync(url) {
  return new Promise(function(resolve, reject) {
    const image = new Image();

    image.onload = function() {
      resolve(image);
    };

    image.onerror = function() {
      reject(new Error('Could not load image at ' + url));
    };

    image.src = url;
  });
}

2、resolve函数和reject函数带有参数

如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。

2.1 resolve

2.1.1 参数为正常值的情况
const p = new Promise((resolve, reject) => {
  resolve('hello');
});

p.then((value) => {
  console.log(value); // hello
});
2.1.2 参数为Promise 实例的情况

当一个 Promise 实例在 resolve 方法中返回另一个 Promise 实例时,当前 Promise 的最终状态将由内部 Promise 实例的状态决定

如下示例:
p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态
如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('这是p1的resolve');
    // reject('这是p1的reject');
  }, 1000);
});

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    // p2 resolve传递 p1 实例
    resolve(p1);
  }, 1000);
});

p2.then((value) => {
  console.log('resolve--', value); // resolve--这是p1的resolve
}).catch((error) => {
  console.log('reject--', error);
});

2.2reject

reject函数的参数通常是Error对象的实例,表示抛出的错误

const p = new Promise((resolve, reject) => {
  reject(new Error('出错了'));
});

p.catch((error) => {
  console.log('报错', error); // 报错Error{}
});

注意,调用resolve或reject并不会终结 Promise 的参数函数的执行。

new Promise((resolve, reject) => {
  resolve(1);
  console.log(2); // 这里仍然会执行
}).then(r => {
  console.log(r);
});
// 2
// 1

3、Promise.prototype.then()

(1)then方法参数:

  • 第一个参数是 resolved 状态的回调函数(可选的)
  • 第二个参数是 rejected 状态的回调函数(可选的)

(2)then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例),因此可以采用链式写法

getJSON("/posts.json").then(function(json) {
  return json.post;
}).then(function(post) {
  // ...
});

(3)当前then里面的回调函数返回的还是一个Promise对象(即有异步操作)时,这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用

function getCount(count) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(count + 1);
    }, 2000);
  });
}

getCount(1)
  .then((val) => {
    console.log(val); // 2
    // 返回的还是一个Promise对象
    return getCount(val);
  })
  .then((val) => {
    console.log(val); // 3
  });

4、Promise.prototype.catch()

(1)Promise.prototype.catch()方法是.then(null, rejection).then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

getJSON('/posts.json').then(function(posts) {
  // ...
}).catch(function(error) {
  // 处理 getJSON 和 前一个回调函数运行时发生的错误
  console.log('发生错误!', error);
});

(2)如果 Promise 状态已经变成resolved,再抛出错误是无效的。

const promise = new Promise(function(resolve, reject) {
  resolve('ok');
  throw new Error('test'); // 无效
});
promise
  .then(function(value) { console.log(value) })
  .catch(function(error) { console.log(error) });
// ok

(3)Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。

getJSON('/post/1.json').then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // some code
}).catch(function(error) {
  // 处理前面三个Promise产生的错误
});

5、Promise.prototype.finally()

finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作

promise
	.then(result => {···})
	.catch(error => {···})
	.finally(() => {···});

6、Promise.all()

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例

const p = Promise.all([p1, p2, p3]); // p1、p2、p3都是 Promise 实例

p的状态由p1、p2、p3决定,分成两种情况:
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数

示例:

const p1 = new Promise(function (resolve, reject) {
  resolve(1);
});
const p2 = new Promise(function (resolve, reject) {
  resolve(2);
});
const p3 = new Promise(function (resolve, reject) {
  resolve(3);
});

const p = Promise.all([p1, p2, p3]);
p.then((list) => {
  console.log(list); // [1, 2, 3]
});

7、Promise.resolve()

将现有对象转为 Promise 对象

Promise.resolve('foo')

等价于:

new Promise(resolve => resolve('foo'))

8、Promise.reject()

Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected

const p = Promise.reject('出错了');

等同于

const p = new Promise((resolve, reject) => reject('出错了'))

三、练习题

1、第1题

new Promise((resolve, reject) => {
  console.log(1);
  resolve();
})
  .then(() => {
    console.log(2);

    return new Promise((resove) => {
      console.log(4)
      resove();
    })
      .then(() => {
        console.log(5);
      })
      .then(() => {
        console.log(6);
      });
  })
  .then(() => {
    console.log(3);
  });

解析:
(1)外部第一个 new Promise 执行,执行完 resolve ,然后执行外部第一个 then
(2)外部第一个 then 方法里面 return 一个 Promise,这个 return 代表 外部的第二个 then 的执行需要等待 return 之后的结果
(3)执行完内部两个 then 之后,再执行 外部的第二个 then

2、第2题

注意:和第一题相差一个 return

// 外部 promise
new Promise((resolve, reject) => {
  console.log(1);
  resolve();
})
  .then(() => {
    // 外部第一个 then
    console.log(2);
	
	// 内部 promise
    new Promise((resove) => {
      console.log(4);
      resove();
    })
      .then(() => {
      	// 内部第一个then
        console.log(5);
      })
      .then(() => {
      	// 内部第二个then
        console.log(6);
      });
  })
  .then(() => {
    // 外部第二个then
    console.log(3);
  });

解析:
重点: 下一个 then 的注册,需要等待上一个 then 的同步代码执行完成

执行顺序:

  1. 外部的 promise 立即执行,打印1;外部 promise 进行 resolve 后,执行外部第一个 then 的注册,外部第二个 then 进入等待状态
  2. 执行外部第一个 then, 打印2;立即执行内部的 promise 打印4;进行 resolve后,内部的第一个 then 注册,内部的第二个 then 进入等待状态;此时外部的第一个 then 的同步操作已经完成,然后开始注册外部第二个 then
  3. 执行内部第一个 then (因为内部第一个then是比外部第一个then先注册的),打印5,然后注册内部第二个 then;
  4. 执行外部第二个 then,打印3
  5. 执行内部第二个 then,打印6

所以最终的顺序:

1
2
4
5
3
6

3、第3题

注意:内部第二个then不是链式调用

// 外部 promise
new Promise((resolve, reject) => {
  console.log(1);
  resolve();
})
  .then(() => {
  	// 外部第一个 then
    console.log(2);
    
	// 内部 promise
    let p = new Promise((resolve, reject) => {
      console.log(4);
      resolve();
    });
    // 内部第一个then
    p.then(() => {
      console.log(5);
    });
    // 内部第二个then,注意这里不是链式调用,这里是跟内部第一个then是同步注册的
    p.then(() => {
      console.log(6);
    });
  })
  .then(() => {
  	// 外部第二个 then
    console.log(3);
  });

解析:
执行内部的 Promise 的 resolve 执行之后,两个同步 p.then 是两个执行代码语句,都是同步执行,自然是会同步注册完。

输出结果:

1
2
4
5
6
3

4、第4题

let p = new Promise((resolve, reject) => {
  console.log(1);
  resolve();
});

p.then(() => {
  console.log(2);

  new Promise((resolve, reject) => {
    console.log(3);
    resolve();
  })
    .then(() => {
      console.log(5);
    })
    .then(() => {
      console.log(6);
    });
});

p.then(() => {
  console.log(4);
});

解析:
外部的注册采用了非链式调用的写法,因此外部的 p.then 是并列同步注册的
内部的第一个 then 注册之后,就开始执行外部的第二个 then 了。然后再依次执行内部的第一个 then ,内部的第二个 then

5、第5题

new Promise((resolve, reject) => {
  console.log(1);
  resolve();
})
  .then(() => {
    console.log(2);

    new Promise((resolve, reject) => {
      console.log(4);
      resolve();
    })
      .then(() => {
        console.log(5);
      })
      .then(() => {
        console.log(6);
      });
      
    return new Promise((resolve, reject) => {
      console.log(7);
      resolve();
    })
      .then(() => {
        console.log(8);
      })
      .then(() => {
        console.log(9);
      });
  })

  .then(() => {
    console.log(3);
  });

解析:
核心:外部的第二个 then ,依赖于内部的 return 的执行结果,所以会等待 return 执行完成
最终输出:

1
2
4
7
5
8
6
9
3

http://www.niftyadmin.cn/n/5352367.html

相关文章

数字艺术展厅有什么好处,搭建数字艺术展厅要注意什么

引言: 数字艺术展厅是一种利用数字科技手段搭建的艺术展览空间,通过数字化展示艺术品,能够为观众带来全新的艺术体验。那么数字艺术展厅有什么好处,搭建数字艺术展厅要注意什么呢? 一、数字艺术展厅的好处 1.创新艺术…

文本检索性能提升 40 倍,Apache Doris 倒排索引深度解读

在 OLAP 领域,Apache Doris 已成为高性能、高并发以及高时效性的代名词。在面向海量数据的复杂查询需求时,除硬件配置、集群规模、网络带宽等因素外,提升性能的核心在于如何最大程度地降低 SQL 执行时的 CPU、内存和 IO 开销,而这…

小程序样例4:个人中心+我的书单

基本功能: 1、展示个人基本信息:头像、昵称 、读书时间统计 2、邮件列表,点击加入计划跳转到书架 3、今日任务 学习进度 4、邮件滑动到最末尾或者最开始,会有弹框提示: 5、图书搜索框 代码分析: 1、邮件…

Ubuntu快捷操作Neo4j,Python脚本,利用py2neo库实现

在Ubuntu上安装了Neo4j数据库,为其编写一个Python脚本,快捷一键实现开启、关闭、清空等操作。 程序内容: 导入所需的模块: subprocess:用于执行系统命令,例如启动、停止、重启Neo4j服务。webbrowser&#…

【云原生】docker-compose单机容器集群编排工具

目录 一、docker-compose容器编排的简介 二、docker-compose的使用 1、docker-compose的安装 2、docker-compose的配置模板文件yaml文件的编写 (1)布尔值类型 (2)字符串类型 (3)一个key有多个值 &am…

Python实现基于持续时间数据进行中介分析(Mediation算法)项目实战

说明:这是一个机器学习实战项目(附带数据代码文档视频讲解),如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 中介分析(Mediation Analysis)是一种统计方法,用于探讨变量之间的因…

2024年数学建模美赛C题(预测 Wordle)——思路、程序总结分享

1: 问题描述与要求 《纽约时报》要求您对本文件中的结果进行分析,以回答几个问题。 问题1:报告结果的数量每天都在变化。开发一个模型来解释这种变化,并使用您的模型为2023年3月1日报告的结果数量创建一个预测区间。这个词的任何属性是否会…

阿里十年 “帕鲁” 手把手带你学习 CompletableFuture

阿里十年 “帕鲁” 手把手带你学习 CompletableFuture 文章目录 阿里十年 “帕鲁” 手把手带你学习 CompletableFutureFuture 介绍CompletableFuture 介绍CompletableFuture 常见操作创建 CompletableFuturenew 关键字静态工厂方法 处理异步结算的结果异常处理组合 Completable…