ES6 入门教程 17 Promise 对象 17.2 基本用法

news2025/1/10 12:28:31

ES6 入门教程

ECMAScript 6 入门

作者:阮一峰

本文仅用于学习记录,不存在任何商业用途,如侵删

文章目录

      • ES6 入门教程
      • 17 Promise 对象
        • 17.2 基本用法

17 Promise 对象

17.2 基本用法

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

下面代码创造了一个Promise实例。

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject

它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

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

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

then方法可以接受两个回调函数作为参数。

第一个回调函数是Promise对象的状态变为resolved时调用,

第二个回调函数是Promise对象的状态变为rejected时调用。

这两个函数都是可选的,不一定要提供。它们都接受Promise对象传出的值作为参数。

下面是一个Promise对象的简单例子。

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

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

上面代码中,timeout方法返回一个Promise实例,表示一段时间以后才会发生的结果。过了指定的时间(ms参数)以后,Promise实例的状态变为resolved,就会触发then方法绑定的回调函数。

在这里插入图片描述

Promise 新建后就会立即执行。

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// resolved

在这里插入图片描述

上面代码中,Promise 新建后立即执行,所以首先输出的是Promise

然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。

下面是异步加载图片的例子。

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;
  });
}

上面代码中,使用Promise包装了一个图片加载的异步操作。

如果加载成功,就调用resolve方法,否则就调用reject方法。

下面是一个用Promise对象实现的 Ajax 操作的例子。

const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  console.error('出错了', error);
});

上面代码中,getJSON是对 XMLHttpRequest 对象的封装,用于发出一个针对 JSON 数据的 HTTP 请求,并且返回一个Promise对象。

需要注意的是,在getJSON内部,resolve函数和reject函数调用时,都带有参数。

如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例,比如像下面这样。

const p1 = new Promise(function (resolve, reject) {
  // ...
});

const p2 = new Promise(function (resolve, reject) {
  // ...
  resolve(p1);
})

上面代码中,p1p2都是 Promise 的实例,但是p2resolve方法将p1作为参数,即一个异步操作的结果是返回另一个异步操作。

注意,这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。

const p1 = new Promise(function (resolve, reject) {
  setTimeout(() => reject(new Error('fail')), 3000)
})

const p2 = new Promise(function (resolve, reject) {
  setTimeout(() => resolve(p1), 1000)
})

p2
  .then(result => console.log(result))
  .catch(error => console.log(error))
// Error: fail

上面代码中,p1是一个 Promise,3 秒之后变为rejectedp2的状态在 1 秒之后改变,resolve方法返回的是p1。由于p2返回的是另一个 Promise,导致p2自己的状态无效了,由p1的状态决定p2的状态。所以,后面的then语句都变成针对后者(p1)。又过了 2 秒,p1变为rejected,导致触发catch方法指定的回调函数。

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

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

在这里插入图片描述

上面代码中,调用resolve(1)以后,后面的console.log(2)还是会执行,并且会首先打印出来。这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。

一般来说,调用resolvereject以后,Promise 的使命就完成了,后继操作应该放到then方法里面,而不应该直接写在resolvereject的后面。

所以,最好在它们前面加上return语句,这样就不会有意外。

new Promise((resolve, reject) => {
  return resolve(1);
  // 后面的语句不会执行
  console.log(2);
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/21638.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java高级】一篇文章带你搞懂线程

目录 | 线程概述 | 线程创建 方式一:继承 Thread 类 方式二:实现 Runnable 接口 一些小细节 方式三:实现 Callable 接口(JDK1.8) | 线程生命周期 生命周期概述 [获取线程信息] 方法 set/getName current [运…

ArcGIS绘制北半球俯视投影地图

做全球碳水循环,植被变化,极端气候相关研究的同学都知道。北半球是核心,因为北半球的核心区域(东亚湿润区,中亚干旱半干旱,青藏高原,阿拉伯半岛,非洲北部沙漠以及美国西部等等核心区): 对于北半球的展示一般采用下面的图: 那么该如何做呢? 熟悉地图学的同学都知道…

Dubbo-聊聊Dubbo协议

前言 Dubbo源码阅读分享系列文章,欢迎大家关注点赞 SPI实现部分 Dubbo-SPI机制 Dubbo-Adaptive实现原理 Dubbo-Activate实现原理 Dubbo SPI-Wrapper 注册中心 Dubbo-聊聊注册中心的设计 Dubbo-时间轮设计 通信 Dubbo-聊聊通信模块设计 什么是协议 在网络交…

【FreeRTOS】FreeRTOS删除任务vTaskDelete()

使用说明: 任务中。小时 (任务句柄_t xTask); INCLUDE_vTaskDelete必须定义为1,才能使用此函数。有关更多信息,请参见RTOS配置文档。 从RTOS内核管理中删除任务。正在删除的任务将从所有就绪、阻止、暂停和事件列表中删…

CEAC 之《计算机应用助理工程师》1

👨‍💻个人主页:微微的猪食小窝 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 微微的猪食小窝 原创 收录于专栏 【CEAC证书】 1组合框有3种不同的类型,这3种类型是下拉式组合框、简单组合框、下拉式列表框&…

12. PyQt5实现多页面切换之QTabBar

PyQt5 QTabBar 类 QTabBar 类直接继承自 QWidget。该类提供了一个选项卡栏,该类仅提供了一个选项卡, 并没有为每个选项卡提供相应的页面,因此要使选项卡栏实际可用,需要自行为每个选项 卡设置需要显示的页面,可以通过 …

【k8s】6、pod详解

文章目录一、pod介绍1、pod的基础概念2、pod定义(资源清单)二、Pod中的容器配置1、基本配置2、镜像拉取(imagePullPolicy)3、启动命令(command)4、环境变量(env)5、端口设置&#xf…

应急响应-计划任务排查

计划任务排查 由于很多计算机都会自动加载“计划任务”,“计划任务”也是恶意病毒实现持久化驻留的一种常用手段,因此在应急响应事件排查时需要进行排查。通俗的讲会定期执行某些操作。 Windows计划任务排查 任务计划是Windows系统的一个预置实现某些…

【数据结构】二叉树的顺序存储结构 —— 堆

文章目录前言二叉树的顺序存储堆的概念和结构堆的实现结构的定义接口总览初始化销毁插入向上调整删除向下调整取堆顶数据计算堆大小判空打印堆完整代码Heap.hHeap.ctest.c结语前言 今天,我们开始二叉树的学习。本篇博客的内容为 介绍二叉树的顺序存储 和 堆的实现。…

【滤波跟踪】基于matlab不变扩展卡尔曼滤波器对装有惯性导航系统和全球定位系统IMU+GPS进行滤波跟踪【含Matlab源码 2232期】

⛄一、简介 针对室内定位中的非视距(Non-Line-of-Sight,NLOS)现象,提出一个新型算法进行识别,同时有效缓解其影响.主要通过超宽带(Ultra-Wideband,UWB)定位系统与惯性导航系统(Inertial Navigation System,INS&#x…

酒店管理系统的设计与实现

Word下载链接如下: https://download.csdn.net/download/yw1990128/87096359 一 设计背景 1.1 课题现状 随着国家社会经济水平的提升,各酒店的发展速度越来越快,入住人员也越来越多。酒店房间的管理要求也愈来愈大,所以很多酒店正…

45.Django模板

1.django模板配置 1.1 Django模板概述 作为一个Web框架,Django需要一种方便的方式来动态生成HTML。最常用的方法依赖于模板。模板包含所需HTML输出的静态部分以及描述如何插入动态内容的特殊语法。 ​ 对模板引擎的一般支持和Django模板语言的实现都存在于 djang…

Linux下的NFS服务(包含windows10下的nfs搭建)

目录 1.NFS服务介绍 2.Linux下搭建NFS服务 (1)下载NFS服务端 (2)新建一个共享文件 (3)修改NFS服务配置文件 (4)重新启动NFS服务 (5)显示查看共享的文件…

38、常用类之String类

1、基本介绍: String s5new String(byte[] b); (5)String实现了Serializable,说明String可以串行化,即可以网络传输 String实现了Comparable,说明String对象可以比较 (6&#xff0…

JavaScript基础(13)_原型、原型对象

上一章构造函数确实简化了多个对象创建的麻烦问题,但是:构造函数每创建一个实例,构造函数就会执行一次,将属性和方法添加到该对象,每个对象实例化后地址互不相同,即使它们的方法所实现的逻辑和功能一样&…

pytorch初学笔记(八):神经网络之卷积操作

目录 一、卷积操作 二、二维卷积操作 2.1 torch.nn.functional 2.2 conv2d方法介绍 2.2.1 使用该方法需要引入的参数 2.2.2 常用参数 2.2.3 关于对input和weight的shape详解 三、代码实战 3.1 练习要求 3.2 tensor的reshape操作 3.3 不同stride的对比 3.4 不同pad…

Docker面试

1. Docker和虚拟机的区别? 虚拟机Virtual Machine与容器化技术(代表Docker)都是虚拟化技术,两者的区别在于虚拟化的程度不同。 隔离性 由于vm对操作系统也进行了虚拟化,隔离的更加彻底。而Docker共享宿主机的操作系统…

数字化转型总体需求

基于“两型三化九力”对企业数字化的要求,以建设产品全生命周期管理平台为手段和途径,打通设计、工艺、制造及交付服务的全生命周期的数字线,实现数字化设计、数字化仿真、数字化制造、数字化服务及数字化管理,未来以此为基础实现…

【计算机毕业设计】11.毕业生信息管理系统+vue

一、系统截图(需要演示视频可以私聊) 摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 毕业生信息招聘平台,主要的模块包括查看管理员;首页、个…

zk常用命令ls、ls2、get、stat,参数意思(重补早期学习记录)

前言:补学习记录,几年前写一半丢草稿箱,突然看到,有强迫症所以补完 1.连接zk客户端(进入zk后台) ./zkCli.sh 连接成功 使用help查看有哪些命令可以使用 试试ls和ls2的区别 ls显示指定路径下的目录 ls2不仅可以 显示指定路径下的目录,还可以显示该节点的相关状态信息…