Js es6 Promise理解和使用

news2024/11/15 21:56:22

js中的promise是一个异步编程的解决方案,语法层面上他是一个构造函数,名字为Promise()。

它的作用就是将一个任务task封装为一个Promise类的实例对象,这个对象会将任务自动运行并得到任务结果,而且在得到结果的过程中并不会影响到其他任务的进行。由此实现多个任务的并发进行。

实现异步的过程被隐藏在Promise类的实现过程中,我们只需要将任务交给Promise,Promise给我们一个instance,之后通过instance去拿任务结果就可以了。我们可以创建多个Promise类的实例instance。

一:Promise构造函数参数和基本使用介绍

1: Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。resolve和reject是两个函数,由JavaScript引擎提供,不用自己部署。

//resolve, reject名称不能修改
const promise = new Promise(function(resolve, reject) {
    // ...some code
    if ( /*异步操作成功,执行resolve方法,目的一般是将某些结果返回出去*/ ) {
        resolve(value);
    } else {
        /*异步操作失败,执行reject方法,目的一般也是将某些结果返回出去*/
        reject(error);
    }
});

2: Promise实例对象的then()方法

Promise 实例生成以后,可以用then方法分别指定resolved状态和rejected 状态的回调函数。也就是对返回的任务结果进行处理。

promise.then(resolved = function(value) {
        // success,对返回的结果value进行处理
    },
    rejected = function(error) {
        //failure,直接把错误类型报给用户
});

3:异步加载图片的例子

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ajax实操</title>
</head>
 
<body>
    <div id="box"></div>
    <script>

        //resolve, reject名称不能修改
		const promise = new Promise(function(resolve, reject) {
		    // ...some code
		    if ( /*异步操作成功,执行resolve方法,目的一般是将某些结果返回出去*/ ) {
		        resolve(value);
		    } else {
		        /*异步操作失败,执行reject方法,目的一般也是将某些结果返回出去*/
		        reject(error);
		    }
		});

        let box = document.getElementById('box');
 
        function GETJSON(url) {
            /*************************************************************/
            function ajaxTask(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("Access-Control-Allow-Origin", "*");
                client.send();
            }
            /*************************************************************/
            return new Promise(ajaxTask);
        };
        /*************************************************************/
        promise = GETJSON("https://www.hupu.com/home/v1/news?pageNo=4&pageSize=50");//出现ajax无法跨域的问题,目前还不会解决
 
        promise.then(
            function(data) {
                console.log(data);;
            },
            function(error) {
                box.innerHTML = '加载失败';
                console.log(error);
            }
        )
    </script>
</body>
</html>

4:有顺序的执行某些请求,我们把每个请求(promise形式)串起来搞成链式调用

//验证
function getAuth(){
    return new Promise((res,rej)=>{
        //关键代码
    })
}
//用户信息
function getUsers(){
    return new Promise((res,rej)=>{
        //关键代码
    })
}
//页面信息
function getPageInfo(){
    return new Promise((res,rej)=>{
        //关键代码
    })
}
//请求顺序:先验证 => 再拿用户 => 再拿页面信息
getAuth().then(res => {
    if(res.success){
        //验证通过,请求用户信息
        return getUsers();
    }else{
        return Promise.reject();
    }
}).then(res => {
    if(res.success){
        //成功获取用户信息,请求页面信息
        return getPageInfo();
    }else{
        return Promise.reject();
    }
}).then(res => {
    if(res.success){
        //成功获取页面信息,反射数据到视图上
 
        //over request
    }
})

5:同时发送多个并行的请求,失败的记录,成功的执行相应的逻辑

function requestMain(urls,successfn,failurefn){
    //图片url资源路径
    let urls = [
     'https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=2363246672,1942618513&fm=58',                      
     'https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=4138785756047,2461366902&fm=58',           
     'https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=378711121878161,3674972757&fm=58',
     'https://ss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2412121295993728,2346220807&fm=58',
    ];
    let errorArr = [];//记录错误的信息
    //构建promise的函数
    function generatePromise(url){
        return new Promise((res,rej)=>{
            //
        })
    }
    urls.reduce((promise,url,index)=>{
        promise.then(res => {
            //请求成功执行的回调
            successfn(res);
        }).catch(err=>{
            //失败时,记录失败信息
            errorArr.push(err);
        }).then(()=>{
            if(index === urls.length-1 && errorArr.length > 1){
                //全部请求完,并且错误数组不为空时执行回调
                failurefn(errorArr);
            }else{
                promise = generatePromise(url)
            }
        })
    },
    Promise.reject(false))
}

6:避免陷入回调地狱

在这里插入图片描述
具体使用:
在这里插入图片描述
在这里插入图片描述
(1) 首先定义三个url的地址;获取第一个url,通过getData(),它return new Promise也就是return一个promise的class的实例。
(2) getData(url1).then 这个then就是new Promise里面的方法,.then(data1 => {console.log(data1) return getData(url2)})。data1就是我们通过url1获取的数据,然后打印出来,这个地方直接return getData(url2),直接return,然后就直接可以再后面.then,我们看data2,然后return getData(url3),.then,最后.catch,它是一个防错处理,万一那一层遇到问题,就会触发error这个回调函数,就会触发catch。
(3) 写法上.then .then .then…… .then都是单层的,是一个管道形式,就是一节对应一节,一节对应一节,它不是一个嵌套形式,不像回调地狱那样,一层一层嵌套。
(4) promise里面还是一个callback的形式,但是它把callback的形式变成了非嵌套的形式,变成了管道式的串联的形式,这就是一个进步,一串一串的形式,串联着走,永远都是一层,这就是promise的一个形式。

二:理论理解

promise是浏览器引擎自带的(但不是所有浏览器都支持promise)
在这里插入图片描述
promise的参数是一个函数且必须有这个函数,否则报错,姑且命名为A函数;

let p = new Promise()
console.log(p); // TypeError: Promise resolver undefined is not a function

A函数里有两个参数,这两个参数也是函数。res和rej这两个参数都是函数,名字随意。
res是成功时的回调
rej是失败时的回调

在这里插入图片描述
new Promise函数是同步函数,并且是立即执行的

promise共有三种状态,pending,fulfilled,rejected

  • 状态只能从pending变为fulfilled状态,成功状态。
  • 或者从pending变为rejected状态,失败状态。

例如:pending转变到fulfilled,状态就确定了,只能是fulfilled状态;如果想转成rejected状态,是不能转的。

当promise刚new出来时,是pending状态:
在这里插入图片描述
promise函数对象有三个属性,如上图展示的,[[Prototype]]其实就是是__ proto__;其他两个属性如下:

PromiseState:就是promise的现在状态:

当你调用res函数,状态立马变为fulfilled(成功状态)
在这里插入图片描述
当你调用rej函数,状态立马变为rejected(失败状态)
在这里插入图片描述
如果两个状态都存在,以谁先调用为准:
在这里插入图片描述

PromiseResult :res或rej返回的结果

PromiseResult就是res或rej执行后的返回的结果,是返给then的。
在这里插入图片描述
当你new 一个promise时,就已经开始自动执行函数。promise是同步的,但then是异步的,要注意区分

promise实例原型上的then函数:

在这里插入图片描述
res函数和rej函数返回的数据,谁来接收的,用then函数

then函数里的参数是两个异步回调函数,是异步的哈,第一个参数函数用于接收res返回来的数据,第二个参数函数用于接收rej返回的数据。

then的第一个参数函数里的形参用来接收res返回的数据:
在这里插入图片描述
then的第二个参数函数里的形参用来接收rej返回的数据:
在这里插入图片描述

其实then里面的函数就是res和rej
在这里插入图片描述
如果new promise中没有写res或rej 则then里的函数不会执行:

let p = new Promise((res,rej)=>{
	
})
p.then(val=>{
	console.log(11); // 11不输出
})

then的返回值:

(1) 如果(父级)上一个then返回的是数据或undefined,则(子级)下个then的状态为成功状态,并将父级返回值返回到子级then的参数里面:

let p = new Promise((res,rej)=>{
	res(11)
})
// 父级then
let p1 = p.then(val=>{
	console.log(val); // 11
	// 默认是return undefined
})
// 子级then ,then中的参数是上一个then返回的值,
p1.then(value=>{
	console.log(value); // undefined
})

在这里插入图片描述

(2) 如果父级then返回的是一个数据:

let p = new Promise((res,rej)=>{
	res(11)
})

let p1 = p.then(val=>{
	console.log(val);
	return {name:'wyy'}
})

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

在这里插入图片描述
(3) 如果父级then抛出的是一个错误,则父级then的状态为失败状态,并将失败状态的值返回给子级then:

通过throw主动抛出错误或者代码出现错误,则promise的状态为rejected,值为throw的值;或者代码出错也为rejected状态,例如输出一个不存在的a;console.log(a)。

第二个then的promise实例状态是根据p.then的返回值决定的

在这里插入图片描述
在这里插入图片描述
如果没有return,则默认为undefined,即是fulfilled状态。

catch

catch是处理rej函数的。当返回错误时调用catch:
在这里插入图片描述
当new promise出现rej(), throw, 语法错误以上三种形式式,就会调用catch函数。

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

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

相关文章

告诉你应该选择 openSUSE 的五大理由

导读多数的的桌面 Linux 用户都会选择三种发行版本&#xff1a;Debian/Ubuntu、Fedora 或者 Arch Linux。但是今天&#xff0c;我将给出你需要使用 openSUSE 的五大理由。相比其他的 Linux 发行版&#xff0c;我总能在 openSUSE 上看到一些令人耳目一新的东西。我说不太好&…

多普勒效应(CSDN_0003_20220909)

目录 1. 机械波的多普勒效应 2. 电磁波的多普勒效应 文章编号&#xff08;CSDN_0003_20220909&#xff09; 由于原文公式较多&#xff0c;所以本文部分内容以截图的形式分享给大家&#xff0c;如果需要电子版原文&#xff0c;可留言或私信。 但凡提高雷达原理和雷达信号处理&a…

【前端】Vue项目:旅游App-(2)TabBar:搭建TabBar、循环获取动态数据、相关工具封装

文章目录目标代码与过程静态htmlcss改成动态数据效果总代码修改或新建的文件tabbarData.jstab-bar.vueload_assetsApp.vue目标 有两种实现方式&#xff1a; 把数据写死&#xff08;静态、直接写在html中&#xff09;动态数据&#xff1a;封装、vite获取动态数据方法 代码与过…

python详解(6)——键盘鼠标操控术(娱乐篇)

目录 本文为原创作品&#xff0c;抄袭必究&#xff01; &#x1f3c6;一、前言 &#x1f3c6;二、pyautogui模块 &#x1f3c6;三、鼠标相关操作 &#x1f6a9;1、鼠标移动 &#x1f6a9;2、获取鼠标位置 &#x1f6a9;3、鼠标点击 &#x1f6a9;4、按松鼠标 &#x1f6a9;5、拖…

笔耕不辍,学习习惯?兴趣爱好?源于对真知的热爱?

干程序员工作、上班赚钱、读书写作、股票投资&#xff0c;加班加点、充满激情&#xff0c;吸金赚钱、养家糊口、为自由和梦想而奋斗&#xff0c;这是比较基础的。 但如果想着奋斗的过程中&#xff0c;充满干劲地做一件事&#xff0c;坚持下去&#xff0c;投入沉迷其中&#xf…

Docker入门介绍

一、Docker介绍 1、Docker是什么&#xff1f; Docker &#xff0c;翻译过来就是码头工人. 虚拟化容器技术。Docker基于镜像&#xff0c;可以秒级启动各种容器。每一种容器都是一个完整的运行 环境&#xff0c;容器之间互相隔离。 Docker是一个开源的应用容器引擎&#xff0…

Ubuntu Linux基本操作+安装工具+安装ROS+g++编译+Cmake

Ubuntu Linux基本操作安装工具安装ROSg编译Cmake 1、进入到根目录 cd /2、回到当前工作空间 cd ~3、查看目录中的内容 lsll4、创建文件夹 mkdir 1235、删除文件夹 rm -rf 123/这里我们在输入要删除的文件夹名时&#xff0c;可以通过按tab键快速补全对应的文件夹名。 按两…

【寒假每日一题】洛谷 P1838 三子棋I

题目链接&#xff1a;P1838 三子棋I - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目描述 小a和uim喜欢互相切磋三子棋。三子棋大家都玩过是吗&#xff1f;就是在九宫格里面OOXX&#xff08;别想歪了&#xff09;&#xff0c;谁连成3个就赢了。 由于小a比较愚蠢&#xf…

《信号与系统实验》实验 3:信号时域抽样和恢复

文章目录 实验内容实验1:抽样定理验证实验f(t)间隔0.5s间隔1s间隔2s验证抽样定理实验2:信号恢复实验间隔0.5s间隔1s间隔2s抽样间隔对于信号恢复过程的影响DAC一阶保持器总结实验内容 实验1:抽样定

HTTPS协议的原理 --- RSA密钥协商算法

目录 一、TLS握手过程 二、RSA密钥协商握手过程 TLS第一次握手 TLS第二次握手 TLS第三次握手 TLS第四次握手 数字证书和CA机构 数字证书签发和验证流程 三、RSA 算法的缺陷 DH 密钥协商算法 一、TLS握手过程 上图简要概述来 TLS 的握手过程&#xff0c;其中每一个「框…

Morris遍历

1、引入 二叉树的遍历 递归实现的方式&#xff1a; public static class Node {public int value;Node left;Node right;public Node(int data) {this.value data;} }//每个节点都是被有限次访问&#xff0c;时间复杂度O(N)&#xff0c;因为每次递归都要存储返回信息&#…

hadoop 集群搭建(详细版)

hadoop 集群搭建更改主机名映射设置免密同步时间创建工作目录下载jdk安装配置Hadoop修改配置文件向其他节点分发配置完成的程序为Hadoop添加环境变量启动集群初始化启动集群web页面web页面:[hdfsweb页面](http://192.168.88.128:9870/)web页面:[yarnweb页面](http://192.168.88…

3.0、Linux-常用目录、文件基本命令

3.0、Linux-常用目录、文件基本命令 命令&#xff1a;ls&#xff08;列出目录&#xff09; ls 命令在 Linux 中是常常被使用到的&#xff0c;因为 Linux 不像 Windows有可视化的界面&#xff1b; -a 参数&#xff1a;all &#xff0c;查看全部的文件&#xff0c;包括隐藏文件&…

【免杀前置课——Windows编程】二十三、内存管理—堆内存管理、虚拟内存管理、文件映射、共享内存、不依靠临界区限制文件多开、DLL注入

内存管理—堆文件映射***文件映射的概念:***共享内存文件多开限制新思路DLL注入远程线程注入远程线程注入.exetest.dll文件映射 文件映射的概念: 文件映射(Mapping&#xff09;是一种将文件内容映射到进程虚拟内存的技术。 映射成功的文件可以用视图,来引用这段内存,从而达到…

中科易安联网智能门锁2022年度总结

时光如梭&#xff0c;步履不辍。在这繁忙而又充实的一年&#xff0c;中科易安从提升服务、优化产品、扩展市场的维度发力&#xff0c;通过扎实的努力、不懈的勤勉&#xff0c;圆满地完成了2022年的工作。接下来&#xff0c;中科易安将为媒体、友商、用户朋友们呈现中科易安2022…

通过Lambda表达式 简单体验一下java方法引用

观看本文前 您需要先掌握 Lambda表达式 如果您之前没有接触过 可以先查看我的文章 java Lambda概念 通过实现线程简单体验一下Lambda表达式 java Lambda表达式的标准格式及其前提带有(代码演示) 然后 我们用 Lambda表达式 写在里面的其实就是一种解决方案 拿参数做操作 那么 …

Qss文件设置Qt界面风格

需要协商才能修改软件界面的风格&#xff0c;所以要留出通用的接口&#xff0c;于是选择使用QSS文件设置软件风格。 一、创建Qss文件 直接创建以.qss为后缀的文件 二、Qt使用Qss文件有两种办法 1、第一种办法&#xff0c;添加资源文件.qrc&#xff0c;然后在qrc文件中添加qss文…

【云边有个小卖部】

童年就像童话&#xff0c;这是他们在童话里第一次相遇。 那么热的夏天&#xff0c;少年的后背被女孩的悲伤烫出一个洞&#xff0c;一直贯穿到心脏。 刘十三被欺负得最惨&#xff0c;却想保护凶巴巴的程霜。 每当她笑的时候&#xff0c;就让他想起夏天灌木丛里的萤火虫&#xff…

Tic-Tac-Toe有多少种不同棋局和盘面状态(python实现)

目录 1. 前言 2. 如何去重&#xff1f; 3. 代码实现 3.1 对称等价判断 3.2 find_neighbor()改造 3.3 主程序及运行结果 4. 延申思考 1. 前言 在前两篇博客中实现了遍历搜索所有的Tic-Tac-Toe的棋局的python程序实现。 Tic-Tac-Toe可能棋局搜索的实现&#xff08;python…