JS-29-Promise对象

一、JavaScript的异步操作

在JavaScript的世界中,所有代码都是单线程执行的。

由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现:

function callback() {console.log('Done');
}
console.log('before setTimeout()');
setTimeout(callback, 1000); // 1秒钟后调用callback函数
console.log('after setTimeout()');

观察上述代码执行,在Chrome的控制台输出可以看到:

before setTimeout()
after setTimeout()
(等待1秒后)
Done

可见,异步操作会在将来的某个时间点触发一个函数调用

AJAX就是典型的异步操作。以上一节的代码为例:

request.onreadystatechange = function () {if (request.readyState === 4) {if (request.status === 200) {return success(request.responseText);} else {return fail(request.status);}}
}

把回调函数success(request.responseText)fail(request.status)写到一个AJAX操作里很正常,但是不好看,而且不利于代码复用。

有没有更好的写法?比如写成这样:

var ajax = ajaxGet('http://...');
ajax.ifSuccess(success).ifFail(fail);

这种链式写法的好处在于,先统一执行AJAX逻辑,不关心如何处理结果,然后,根据结果是成功还是失败,在将来的某个时候调用success函数或fail函数。

古人云:“君子一诺千金”,这种“承诺将来会执行”的对象在JavaScript中称为Promise对象。

1-1、setTimeout函数

setTimeout 是 JavaScript 中一个非常常用的函数,用于在指定的延迟后执行一个函数或计算一个表达式。它返回一个代表定时器的ID,这个ID可以用来在将来必要的时候取消定时器(使用 clearTimeout 函数)。

语法:

var timerId = setTimeout(func|code, [delay], [arg1], [arg2], ...)
  • func|code:要执行的函数或要计算的表达式。
  • delay:可选参数,表示延迟的毫秒数,即多长时间后执行函数或表达式。默认是 0。
  • arg1, arg2, ...:可选参数,表示传递给函数的额外参数。

示例:

setTimeout(function() {  console.log('Hello, world!');  
}, 2000);

在这个例子中,console.log('Hello, world!') 将在 2 秒(2000 毫秒)后执行。

function greet(name) {  console.log('Hello, ' + name + '!');  
}  setTimeout(greet, 2000, 'Alice');

在这个例子中,greet 函数将在 2 秒后执行,并且会传递 'Alice' 作为参数。

setTimeout 只会执行一次指定的函数或代码。如果你想要重复执行某个函数或代码,你应该使用 setInterval 或者在函数内部再次调用 setTimeout

1-2、清除定时器 clearTimeout 函数

如果你想要在某个时刻取消定时器,你可以使用 clearTimeout 函数,并传入 setTimeout 返回的定时器ID。

语法:

clearTimeout(timeoutID)

示例1: 

var timerId = setTimeout(function() {  console.log('This will not be logged.');  
}, 5000);  // 假设在某个时刻,我们决定取消这个定时器  
clearTimeout(timerId);

在这个例子中,由于我们调用了 clearTimeout,所以 console.log 不会被执行。

示例2:

// 设置一个定时器,将在 2 秒后执行  
var timerId = setTimeout(function() {  console.log('Timer executed!');  
}, 2000);  // 在 1 秒后取消定时器  
setTimeout(function() {  clearTimeout(timerId);  console.log('Timer cleared!');  
}, 1000);

你将在控制台看到 "Timer cleared!" 的输出,而不会看到 "Timer executed!" 的输出。

1-3、链式调用

链式调用,允许我们在单个对象上连续调用多个方法,并且每次方法调用都返回同一个对象,以便可以进一步调用其他方法。

优点:这种模式可以提高代码的可读性和简洁性。

 1-4、Promise对象

Promise有各种开源实现,在ES6中被统一规范,由浏览器直接支持。

在JavaScript中,Promise对象用于处理异步操作,它代表了一个可能现在、将来或永远不可用的值。

Promise对象有三种状态pending(进行中)、fulfilled(已成功)和rejected(已失败)。一旦Promise的状态从pending变为fulfilledrejected,就不会再改变。

创建Promise对象的基本语法如下:

const promise = new Promise((resolve, reject) => {  // 异步操作代码  if (/* 异步操作成功 */) {  resolve(value); // 将Promise的状态设置为fulfilled,并传递一个值  } else {  reject(error); // 将Promise的状态设置为rejected,并传递一个错误  }  
});

 resolvereject都是函数,它们由Promise构造函数传递进来,用于处理异步操作的结果。

示例:

const promise = new Promise((resolve, reject) => {  setTimeout(() => {  const success = true;  if (success) {  resolve('异步操作成功!');  } else {  reject('异步操作失败!');  }  }, 1000);  
});  promise.then(value => {  console.log(value); // 如果Promise状态为fulfilled,则执行这里的代码  
}).catch(error => {  console.error(error); // 如果Promise状态为rejected,则执行这里的代码  
});

在JavaScript的Promise构造函数中,resolvereject是两个非常关键的函数参数。它们被用来改变Promise对象的状态,并传递最终的结果或错误给Promise链中的后续处理函数。

1、resolve函数

resolve函数用于将Promise对象的状态从pending(进行中)变为fulfilled(已完成),并传递一个值给后续的.then()处理函数

2、reject函数

reject函数用于将Promise对象的状态从pending变为rejected(已拒绝),并传递一个错误对象给后续的.catch()处理函数

3、Promise链中的错误处理

Promise链中,如果你没有在每个.then()之后立即使用.catch()来处理可能发生的错误。

你可以在链的末尾使用单个.catch()来捕获所有之前的.then()中可能抛出的错误。这是因为,一旦Promise链中的某个环节发生错误,该错误会“冒泡”到链的末尾,除非在某个环节被捕获处理。

promise  .then(result => {  // 处理结果...  // 如果这里发生错误且没有捕获,它会传递到链的末尾的.catch()中  })  .then(anotherResult => {  // 处理另一个结果...  // 同样,这里的错误也会“冒泡”到链的末尾  })  .catch(error => {  // 处理链中任何环节的错误  console.error(error);  });

我们先看一个最简单的Promise例子:

生成一个0-2之间的随机数,如果小于1,则等待一段时间后返回成功,否则返回失败:

    <div id="test-promise-log" style="border: solid 1px #ccc; padding: 1em; margin: 15px 0;"><p>Log:</p></div><script>"use script"function testLian(){// 清除log:var logging = document.getElementById('test-promise-log');while (logging.children.length > 1) {logging.removeChild(logging.children[logging.children.length - 1]);}// 输出log到页面:function log(s) {var p = document.createElement('p');p.innerHTML = s;logging.appendChild(p);}new Promise(function (resolve, reject) {log('start new Promise...');var timeOut = Math.random() * 2;log('set timeout to: ' + timeOut + ' seconds.');setTimeout(function () {if (timeOut < 1) {log('call resolve()...');resolve('200 OK');}else {log('call reject()...');reject('timeout in ' + timeOut + ' seconds.');}}, timeOut * 1000);}).then(function (r) {log('Done: ' + r);}).catch(function (reason) {log('Failed: ' + reason);});}</script>

可见Promise最大的好处是在异步执行的流程中,把执行代码处理结果的代码清晰地分离了:

4、Promise处理若干异步任务

Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。

串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码。有了Promise,我们只需要简单地写:

job1.then(job2).then(job3).catch(handleError);

其中,job1job2job3都是Promise对象。

下面的例子演示了如何串行执行一系列需要异步计算获得结果的任务:

// 0.5秒后返回input*input的计算结果:
function multiply(input) {return new Promise(function (resolve, reject) {log('calculating ' + input + ' x ' + input + '...');setTimeout(resolve, 500, input * input);});
}// 0.5秒后返回input+input的计算结果:
function add(input) {return new Promise(function (resolve, reject) {log('calculating ' + input + ' + ' + input + '...');setTimeout(resolve, 500, input + input);});
}var p = new Promise(function (resolve, reject) {log('start new Promise...');resolve(123);
});p.then(multiply).then(add).then(multiply).then(add).then(function (result) {log('Got value: ' + result);
});

setTimeout可以看成一个模拟网络等异步执行的函数。

1-5、AJAX异步执行函数转换为Promise对象

现在,我们把上一节的AJAX异步执行函数转换为Promise对象,看看用Promise如何简化异步处理:

'use strict';// ajax函数将返回Promise对象:
function ajax(method, url, data) {var request = new XMLHttpRequest();return new Promise(function (resolve, reject) {request.onreadystatechange = function () {if (request.readyState === 4) {if (request.status === 200) {resolve(request.responseText);} else {reject(request.status);}}};request.open(method, url);request.send(data);});
}var log = document.getElementById('test-promise-ajax-result');
var p = ajax('GET', '/api/categories');
p.then(function (text) { // 如果AJAX成功,获得响应内容log.innerText = text;
}).catch(function (status) { // 如果AJAX失败,获得响应代码log.innerText = 'ERROR: ' + status;
});

1-6、Promise.all()

除了串行执行若干异步任务外,Promise还可以并行执行异步任务。

试想一个页面聊天系统,我们需要从两个不同的URL分别获得用户的个人信息和好友列表,这两个任务是可以并行执行的,用Promise.all()实现如下:

        "use script"var p1 = new Promise(function (resolve, reject) {setTimeout(resolve, 500, 'A1');});var p2 = new Promise(function (resolve, reject) {setTimeout(resolve, 600, 'A2');});// 同时执行p1和p2,并在它们都完成后执行then:Promise.all([p1, p2]).then(function (results) {// 获得一个Array: ['A1', 'A2']console.log(results);});

1-7、Promise.race()

有些时候,多个异步任务是为了容错

比如,同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可。这种情况下,用Promise.race()实现:

var p1 = new Promise(function (resolve, reject) {setTimeout(resolve, 500, 'A1');
});
var p2 = new Promise(function (resolve, reject) {setTimeout(resolve, 600, 'A2');
});
Promise.race([p1, p2]).then(function (result) {console.log(result); // 'A1'
});

由于p1执行较快,Promise的then()将获得结果'A1'p2仍在继续执行,但执行结果将被丢弃

如果我们组合使用Promise,就可以把很多异步任务以并行和串行的方式组合起来执行。

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

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

相关文章

temux安装debian自用记录

http://ip:9001/ user/123 http://ip:5705/index admin/drpy 一、安装Ubuntu1804 1&#xff0e;首先安装termux.app 2&#xff0e;启动该app&#xff0c;输入命令 curl -Lo l l.tmoe.me; sh l 3&#xff0e;运行过程中连续选“Y”&…

ip数据报

IP数据报格式详解 在 TCP/IP 协议中&#xff0c;使用 IP 协议传输数据的包被称为 IP 数据包&#xff0c;每个数据包都包含 IP 协议规定的内容。IP 协议规定的这些内容被称为 IP 数据报文&#xff08;IP Datagram&#xff09;或者 IP 数据报。 IP 数据报文由首部&#xff08;称…

Linux学习-数据库

数据库软件: 关系型数据库: Mysql Oracle SqlServer Sqlite 非关系型数据库&#xff1a; Redis NoSQL 1.数组、链表、文件、数据库 数组、链表: 内存存放数据的方式(代码运行结束、关机数据丢失) 文件、…

GitHub repository - Branch - SSH clone URL - Clone in Desktop - Download ZIP

GitHub repository - Branch - SSH clone URL - Clone in Desktop - Download ZIP 1. Branch2. SSH clone URL3. Clone in Desktop4. Download ZIPReferences 1. Branch 显示当前分支的名称。从这里可以切换仓库内分支&#xff0c;查看其他分支的文件。 2. SSH clone U…

每日汇评:黄金会在鲍威尔讲话之前重回 2,400 美元吗?

在避险情绪的影响下&#xff0c;金价在 2400 美元下方巩固反弹&#xff1b; 尽管中东紧张局势有所缓和&#xff0c;美元仍因美国零售销售数据强劲而上涨&#xff1b; 由于有利的四小时技术结构&#xff0c;金价的看涨潜力仍然完好无损&#xff1b; 周二亚洲交易中&#xff0c;金…

智能装箱机:打造高效物流新时代的革命性工具

在快节奏的现代生活中&#xff0c;物流行业的效率与智能化水平直接关系到消费者的购物体验和企业的市场竞争力。装箱机作为物流包装中重要的一个环节&#xff0c;其智能化升级已成为行业发展的必然趋势。星派将与大家探讨装箱机为什么说是智能化装箱解决方案? 一、装箱机的智能…

喜讯 | “泰迪杯”数据挖掘挑战赛再次进入计算机类竞赛指数榜单

4月15日&#xff0c;第61届中国高等教育博览会在福州召开。在教师教学发展与创新人才培养论坛上&#xff0c;浙江大学何钦铭教授代表《全国普通高校大学生计算机类竞赛指数》专家工作组发布了最新一年的竞赛指数。据悉&#xff0c;今年的竞赛项目清单包含了28项赛事&#xff0c…

20.java openCV4.x 入门-Imgproc之点集拟合

专栏简介 &#x1f492;个人主页 &#x1f4d6;心灵鸡汤&#x1f4d6;我们唯一拥有的就是今天&#xff0c;唯一能把握的也是今天建议把本文当作笔记来看&#xff0c;据说专栏目录里面有相应视频&#x1f92b; &#x1f4f0;专栏目录 Imgproc之点集拟合 一、拟合直线1.字段…

Android11应用安装未知来源的权限改动

最近开发的App需要下载安装另一个App。这就涉及到了app的安装代码。关于App的安装代码&#xff0c;写了不少&#xff0c;所以这一块觉得不是问题&#xff1a; 判断版本&#xff0c;Android8.0判断是否有未知来源安装全选&#xff0c;没有则打开未知来源安装权限设置界面去开启…

【团体程序设计天梯赛 往年关键真题 详细分析完整AC代码】L2-001 紧急救援(最短路+路径打印) L2-002 链表去重(模拟链表)

L2-001 紧急救援 最短路路径打印 作为一个城市的应急救援队伍的负责人&#xff0c;你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时…

C语言:文件操作(三)

目录 前言 5、文章的随机读写 5.1 fseek 5.2 ftell 5.3 rewind 结语 前言 本篇文章继续讲解文件操作&#xff0c;讲解文件的随机读写&#xff0c;主要有三个函数&#xff1a;fseek&#xff1b;ftell&#xff1b;rewind。 前面讲解的函数都是对文件内容进行顺序读写&#x…

win10 64位装三菱PLC软件出现oleaut32.dll拒绝访问

win10 64位装 三菱PLC软件GX works2出现以下情况&#xff1a;以下文件没有自注册或撤消注册 c:/Windows/SysWOW64/oleaut32.dll拒绝访问 经过百度说是兼容问题 解决方案&#xff1a;在安装包启动图标上右键-兼容性疑难解答-尝试建议的设置-测试程序。 点击测试程序后setup正常…

C/C++ C/C++ 入门(6)模板初阶

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;C 多多指教&#xff01; 一、泛型编程 在之前&#xff0c;我们进行编程的时候&#xff0c;总是针对于某一个具体的问题。就比如说&#xff0c;如何实现一个int类型的swap函数呢&#xff1f;大家肯定会写。…

【计算机网络】常用编码方式+例题(曼彻斯特编码、差分曼彻斯特编码...)

常用编码方式例题 常用编码方式练习画出四种编码20221题342015题342013题34 常用编码方式 练习 画出四种编码 20221题34 这个题目的考察是差分曼彻斯特编码。 差分曼彻斯特编码在每个码元的中间时刻电平都会发生跳变。与曼彻斯特编码不同的是&#xff1a;电平的跳变仅代表时钟…

【随笔】Git 基础篇 -- 拉取数据 git pull(二十八)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

2024全网最全的Postman接口自动化测试!

| 背景 该篇文章针对已经掌握 Postman 基本用法的读者&#xff0c;即对接口相关概念有一定了解、已经会使用 Postman 进行模拟请求的操作。 当前环境&#xff1a; Window 7 - 64 Postman 版本&#xff08;免费版&#xff09;&#xff1a;Chrome App v5.5.3 不同版本页面 U…

哪个品牌短袖穿着舒服?夏季舒适透气的五款短袖分享

近期很多地区的天气都开始变得热了&#xff0c;尤其是华南地区已经开始穿上短袖了。很多朋友都想选一些夏天穿的短袖&#xff0c;但是市面上的短袖品牌实在太多&#xff0c;看得大家眼花缭乱难以选择&#xff0c;而且还有不少质量差的短袖混杂在其中。 基于我对多个品牌的测评以…

[数据结构]—二叉树基本概念

1.树概念及结构 1.树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有一个特殊的结点&#xff…

20240412-算法复习打卡day52||● 300.最长递增子序列 ● 674. 最长连续递增序列 ● 718. 最长重复子数组

300.最长递增子序列 从前往后遍历即可 class Solution { public:int lengthOfLIS(vector<int>& nums) {if (nums.size() < 1) return nums.size();vector<int> dp(nums.size(), 1);int result 0;for (int i 1; i < nums.size(); i) {for (int j 0; …

适合 Python 入门的 8 款强大工具

Python是一种开源的编程语言&#xff0c;可用于Web编程、数据科学、人工智能以及许多科学应用。学习Python可以让程序员专注于解决问题&#xff0c;而不是语法。由于Python相对较小&#xff0c;且拥有各式各样的工具&#xff0c;因此比Java和C等语言更具优势&#xff0c;同时丰…