Promise(基础)

news2024/11/28 10:44:29

Promise是什么

1.promise是一门新的技术(ES6规范)
2.Promise是JS中一编程的解决方案(旧的解决方案是单纯的使用回调函数)
3.promise一个构造函数,promise队形用来封装一个一步操作并可以获取其成功/失败的结果值。
注常见的异步操作:文件操作、数据库操作、AJAX、定时器

那么promise有哪些优势呢?
1.支持链式调用
2.解决地狱回调的问题(地狱回调就是,在回调中嵌套回调),不易于代码的维护。

promise hello world

// 普通的异步任务
<body>
    <button id="btn">点击抽奖</button>
</body>
<script>
    const but = document.getElementById("btb");
    btn.addEventListener('click', function () {
        setTimeout(() => {
            const n = Math.random(1, 100);
            if (n <= 0.3) alert("中奖了");
            else alert("没有中奖");
        }, 1000)
    })
</script>

promise写法

// 用promise包裹异步操作
<body>
    <button id="btn">点击抽奖</button>
</body>
<script>
    const but = document.getElementById("btb");
    btn.addEventListener('click', function () {
        // 参数为函数类型
        const p = new Promise((resolve, reject) => {
            setTimeout(() => {
                const n = Math.random(1, 100);
                if (n <= 0.3) resolve();
                else reject();
            }, 1000)
        });
        // 指定回调,成功执行resolve函数,执行失败执行reject函数
        p.then(() => {
            alert("中奖了");
        }, () => {
            alert("没有中奖")
        })
    })
</script>

如果要传递参数

const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        const n = Math.random(1, 100);
        if (n <= 0.3) resolve(n);
        else reject(n);
    }, 1000)
});
// 指定回调时接受参数
p.then((val) => {
    alert("中奖了" + val);
}, (val) => {
    alert("没有中奖" + val)
})

promise基础实践(熟悉写法)

  • 文件操作(需要node环境)
// 普通代码
const fs = require('fs');
fs.readFile('./data.txt', (err, data) => {
    if (err) console.log(err);
    else console.log(data);
})

promise封装

// promise封装
const fs = require('fs');
const p = new Promise((resolve, reject) => {
    fs.readFile('./data.txt', (err, data) => {
        if (err) reject(err);
        else resolve(data);
    })
})
p.then((data) => {
    console.log("读取文件成功!!!")
    console.log(data)
}, (err) => {
    console.log("读取文件成功!!!")
    console.log(err)
})
  • ajax封装
// 原始写法
var XMLHttpRequest = require('xhr2');
function send() {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", "http://127.0.0.1:8888");
    xhr.send();
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status <= 300) {
                console.log("成功!!!")
                console.log(xhr.response)
            } else {
                console.log("失败!!!")
                console.log(xhr.status)
            }
        }
    }
}
send()
// promise写法
const p = new Promise((resolve, reject) =>{
    const xhr = new XMLHttpRequest();
    xhr.open("GET", "http://127.0.0.1:8888");
    xhr.send();
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status <= 300) {
                console.log("成功!!!")
                resolve(xhr.response);
            } else {
                console.log("失败!!!")
                reject(xhr.status);
            }
        }
    }
})
p.then((data) => {
    console.log(data)
}, (err) => {
    console.log(err)
})

Promise知识点

  • util.promisify promise对象转换
const fs = require("fs")
const util = require("util");
// 将回调函数转换为promise对象
const  preadFile = util.promisify(fs.readFile)
preadFile("./data.txt").then((data) => {
    console.log(data.toString())
});
  • promise的状态改变
    promise实例的[promiseState]
  • pendging 未决定的
  • resolved/fullfilled 成功
  • rejected 失败
    promise的状态改变只有两种情况:
    pending 变为resolved
    pending 变为rejected
  • promise 对象的值
    实实例属性[promiseResult] 保存着对象[成功/失败]的结果
    只有resolve和reject函数可以修改这个结果值

  • promise的工作流程
    在这里插入图片描述

  • Promise API
    1)Promise构造函数 Promise(excutor) {}
    executor函数 : 执行器(resolve, reject) => {}
    resolve函数 : resolve
    reject函数 : reject

2)Then方法 (onResolved, onRejected) => {}
onRedolved函数 : 成功的回调函数
onRejected函数 : 失败的回调函数

3)Promise.prototype.catch 方法 (onrejected)=> {}
onRejected 函数:失败的回到
注:这个方法只能指定失败的回调函数

4)Promise.resolve()

// 如果resolve中传入的参数为非promise对象则返回的结果为resolve的结果,成功的结果为参数
// 如果传入的参数为promise对象结果取决于参数的结果
let p = Promise.resolve(521)
console.log(p)

let p = new Promise(new Promise((resolve, reject) => {}));

5)Promise.reject()

// 如果resolve中传入的参数为非promise对象则返回的结果为reject的结果,失败的结果就是参数
// 如果传入的参数为promise对象结果取决于参数的结果
let p = Promise.reject(521)
console.log(p)

let p = new Promise(new Promise((resolve, reject) => {}));

6)Promise.all()
包含n个promise数组,结果返回一个新的promise,只有所以的promise都成功才成功,只要有一个失败就是败。

let p1 = new Promise((resolve, reject) => {
    resolve('ok')
})
let p2 = Promise.resolve("ok");
let p3 = Promise.reject("error");
const res = Promise.all([p1, p2, p3])
console.log(res)

7)Promise.race()
返回一个新的promise对象,第一个完成的promise的状态就是最终的状态。
应用场景:比如提供了多个接口,效率不一样谁先返回用谁的结果。

8)改变promise的状态
初始状态为pending,之后可以调用resolve和reject改变状态,throw爆出错误也可以改变promise的状态。
9)Promise指定多个成功回调会执行吗

let p = new Promise((resolve, reject) => {
    resolve('ok')
})
p.then(v => {
    console.log(v)
})
p.then(v => {
    console.log(v + 1)
})
// 验证可知多个回调都会执行,如果Promise一直为pending状态则不会执行

10)改变状态和指定函数回调谁先谁后?
都有可能
如果promise中是同步任务则是先改变状态,然后指定回调。如果是异步任务则可能是先指定回调然后再改变状态
11)then链式调用

let p = new Promise((resolve, reject) => {
    resolve('ok')
})
p.then(() =>{
    return new Promise((resolve, reject) => {
        resolve("success")
    })
}).then(v => {
    console.log(v)
}).then(v => {
    // 输出undifined,因为上一个thenPromise的返回结果没有写
    console.log(v)
})

12)异常穿透
通过then链式调用的时候发生错误可以在最终来进行指定回调来处理。

let p = new Promise((resolve, reject) => {
    resolve('ok')
})
p.then(() =>{
    return new Promise((resolve, reject) => {
        reject("err")
    })
}).then(v => {
    console.log(v)
}).then(v => {
    // 输出undifined
    console.log(v)
}).catch((err) => {
    console.log(err)
})

13)终端promise链
需要在then方法中返回一个pending状态的promise才能终端promise链

Promise 自定义封装

此部分需要多写多练

class Promise {
    constructor(executor) {
        this.promiseState = "pending"
        this.promiseResult = null
        // 用于保存异步任务的回调函数
        this.callbacks = []
        // 这里需要注意this问题
        // 可以先存下来self = this 后面用self替代this
        const self = this;
        function resolve(data) {
            // 保证状态只改变一次
            if (self.promiseState !== "pending") return
            self.promiseState = 'resolved'
            self.promiseResult = data
            // 指定多个回调
            // 使得它进入异步队列,用定时器包裹
            setTimeout(() => {
                self.callbacks.forEach(item => {
                    item.onResolved(data);
                })
            })

        }
        function reject(data) {
            if (self.promiseState !== "pending") return
            self.promiseState = 'rejected'
            self.promiseResult = data
            // 指定多个回调
            setTimeout(() => {
                self.callbacks.forEach(item => {
                    item.onRejected(data);
                })
            })

        }
        try {
            executor(resolve, reject);
        } catch (err) {
            // 直接调用reject函数改变状态为rejected
            reject(err)
        }
    }
    then(onResolved, onRejected) {
        const self = this;
        // 异常穿透的逻辑
        if (typeof onRejected !== "function") {
            onRejected = reason => {throw reason};
        }
        if (typeof onResolved !== "function") {
            onResolved = value => value;
        }
        return new Promise((resolve, reject) => {
            function callback(method) {
                try {
                    let result = method(self.promiseResult)
                    // 如果返回的是promise对象,promise的结果取决于这个promise的结果
                    if (result instanceof Promise) {
                        result.then(v => {
                            resolve(v);
                        }, e => {
                            reject(e)
                        })
                    } else {
                        // 如果返回的是值,promise的结果就是这个值
                        resolve(result)
                    }
                } catch (e) {
                    reject(e)
                }
            }

            if (this.promiseState === "resolved") {
                setTimeout(() => {
                    callback(onResolved)
                })

            } else if (this.promiseState === "rejected") {
                setTimeout(() => {
                    callback(onRejected)
                })
            } else {
                // 这里异步任务先指定回调,由于可以指定多个回调所以用数组保存
                this.callbacks.push({
                    onResolved: function () {
                        callback(onResolved)

                    },
                    onRejected: function () {
                        callback(onRejected)
                    }
                });
            }
        })
    }
    catch(onRejected) {
        return this.then(undefined, onRejected)
    }
    static resolve(value) {
        return new Promise((resolve, reject) => {
            if (value instanceof Promise) {
                value.then(v => {
                        resolve(v)
                    },
                    e => {
                        reject(e)
                    })
            } else {
                resolve(value)
            }
        })
    }
    static reject(reason) {
        return new Promise((resolve, reject) => {
            reject(reason);
        })
    }
    static all(promise) {
        return new Promise((resolve, reject) => {
            let count = 0;
            const res = [];
            for (let i = 0; i < promise.length; i++) {
                promise[i].then((v) => {
                    res[i] = v
                    count++;
                }, (r) => {
                    reject(r)
                })
                if (count == promise.length) {
                    resolve(res);
                }
            }
        })
    }

    static race(promise) {
        return new Promise((resolve, reject) => {
            for (let i = 0; i < promise.length; i++) {
                promise[i].then((v) => {
                    resolve(v)
                }, (r) => {
                    reject(r)
                })
            }
        })
    }
}

参考视频:
Promise教程

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

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

相关文章

sparksql案例实操

sparksql案例实操解决语句如下 select * from( select , rank()over(partition by area order by clickCnt desc) from(select area, product_name, count()as clickCnt from( select a.*, p.product_name, c.area, c.city_name from user_visit_action a join product_info p…

Dubbo与Spring集成

Dubbo框架常被当作第三方框架集成到应用中&#xff0c;当Spring集成Dubbo框架后&#xff0c;为什么在编写代码的时候&#xff0c;只用了DubboReference注解就可以调用提供方的服务了呢&#xff1f;这篇笔记就是分析Dubbo框架是怎么与Spring结合的。 现状integration层代码编写…

关于嵌入式学习和规划,求指点?

在知乎上收到的一个提问问题&#xff1a;各位大佬好&#xff0c;我先说说基本情况&#xff0c;28岁&#xff0c;北京&#xff0c;嵌入式软开&#xff0c;军工行业。硕士毕业一年半。工作不忙收获很少&#xff0c;造成我自己特别迷茫&#xff0c;没有了方向&#xff0c;自己学没…

【C++】Hash闭散列

目录 一、哈希的概念 1.1 哈希冲突 1.2 哈希函数 1.3 装载因子 二、闭散列 2.1 线性探测 2.2 Insert 插入 2.3 Find 查找 2.4 Erase删除 2.5 插入复杂类型 2.6 二次探测 三、源代码与测试用例 3.1 hash源代码 3.2 测试用例 一、哈希的概念 在前面学习了二叉搜索…

多巴胺聚乙二醇多巴胺,Dopamine-PEG-Dopamine简介,多巴胺是具有正性肌力活动的单胺化合物

产品名称&#xff1a;多巴胺聚乙二醇多巴胺&#xff0c;双多巴胺聚乙二醇&#xff08;Dopamine-PEG-Dopamine&#xff09; 中文别名&#xff1a;多巴胺PEG多巴胺&#xff0c;双多巴胺聚乙二醇 英文名称&#xff1a;Dopamine-PEG-Dopamine 存储条件&#xff1a;-20C&#xff0…

磨金石教育影视技能干货分享|浅析中国CG特效的发展现状

中国CG特效的发展2015年是一个分水岭。在2015年之前&#xff0c;中国CG 特效发展是混乱的&#xff0c;不成熟的。总体表现就是技术水平不足&#xff0c;缺少人才培养的体系。当时从事CG的公司&#xff0c;大概有两个类型&#xff1a;“技术型与业务型”。所谓技术型的公司&…

设计模式_结构型模式 -《装饰器模式》

设计模式_结构型模式 -《装饰器模式》 笔记整理自 黑马程序员Java设计模式详解&#xff0c; 23种Java设计模式&#xff08;图解框架源码分析实战&#xff09; 概述 我们先来看一个快餐店的例子。 快餐店有炒面、炒饭这些快餐&#xff0c;可以额外附加鸡蛋、火腿、培根这些配菜…

PowerDesigner设计表时显示注释列Comment

首先&#xff0c;使用 PowerDesigner 新建模型&#xff0c;File —> New Model 然后&#xff0c;切换到模型类型(Model types)选项卡&#xff0c;选中 Physical Diagram 然后点击右侧表格图标&#xff0c;在左侧面板中创建表格如下。双击表格&#xff0c;找到Columns选项卡…

招标采购中,如何编写有效的RFI(信息邀请书)?

在企业招标采购过程中&#xff0c;RFI&#xff08;信息邀请书&#xff09;是一个从商品或服务的潜在供应商处收集信息的正式流程。RFI旨在由客户编写并发送给潜在供应商。RFI通常是第一个也是最广泛的一系列请求&#xff0c;旨在缩小潜在供应商候选人名单。 当企业对潜在供应…

【实际开发07】- XxxxController 批量处理 × 5 -【model】

目录 1. Mode 1. IotTypeController 基础 7 tips 2. 辅助添加 Validated 无法覆盖的 参数校验 1. 预处理空指针异常 ( 校验 : 核心必填参数 not null ) 3. RequestBody 对应API 存在 feign 调用时 , 注意 : 不可缺省 1. feign API 需要加 RequestBody , Controller 层可…

手工测试 | 黑盒测试方法论—边界值

本文节选自霍格沃兹测试学院内部教材 边界值分析法是一种很实用的黑盒测试用例方法&#xff0c;它具有很强的发现故障的能力。边界值分析法也是作为对等价类划分法的补充&#xff0c;测试用例来自等价类的边界。 这个方法其实是在测试实践当中发现&#xff0c;Bug 往往出现在定…

OpenCV4.6 VS 4.7 QRCode解码功能效果对比

导 读 本文主要对OpenCV4.7.0和4.6.0中QRCode检测/解码功能做简单的测试对比&#xff0c;供大家参考。 背景介绍 最近OpenCV更新到了4.7.0版本&#xff0c;在ChangeLog算法部分除了新增Stackblur滤波算法(详细介绍见下面链接)&#xff0c;还有对QRCode检测和解码的改进。 吊打…

实现通讯录(C语言)

功能实现 实现步骤&#xff1a; 创建通讯录 初始化通讯录 打印菜单 实现选择功能 实现添加功能 实现删除功能 实现查找功能 实现修改功能 实现清空功能 实现排序功能 实现查询所有联系人信息功能 通讯录总代码 创建通讯录 1、创建成员信息结构体 我们用结构体来封装一个联系人…

【系列04】数组 多维数组 冒泡排序 稀疏数组[有目录]

数组声明和创建 变量类型 变量名称 变量的值 声明数组 int []nums;//定义//上面是首选 /*也可以 int nums2[];*/下面这种写法是为了迎合c与c用户的喜爱,更推荐用上面的定义 方式 创建数组 numsnew int[10];定义数组计算数组的和 package com.SunAo.array; //变量类型 变量名称…

TypeScript 数据模型层编程的最佳实践

虽然 TypeScript 主要用于客户端&#xff0c;而数据模型的设计主要是服务端来做的。 但是要写出优雅的代码&#xff0c;也还是有不少讲究的。 让我们从一个简单的我的文章列表 api 返回的数据开始&#xff0c;返回的文章列表的信息如下&#xff1a; {"id": 2018,&qu…

原生PHP及thinkphp6接入阿里云短信

申请accesskey获取到Accesskey ID和Accesskey Secret保存下来&#xff0c;一会要用到添加测试手机号&#xff0c;在接口测试能否正常发送下载阿里云短信sdk&#xff0c;使用composer下载&#xff0c;没有安装请先安装安装可以安装到任意文件夹下&#xff0c;后面代码写好后&…

TDSQL的安装教程(低配体验)

一、了解TDSQL tdsql腾讯云文档 TDSQL-C MySQL 版&#xff08;TDSQL-C for MySQL&#xff09;是腾讯云自研的新一代云原生关系型数据库。融合了传统数据库、云计算与新硬件技术的优势&#xff0c;为用户提供具备极致弹性、高性能、海量存储、安全可靠的数据库服务。TDSQL-C My…

AtCoder Beginner Contest 285解题报告

A - Edge Checker 2 Problem Statement Determine if there is a segment that directly connects the points numbered a and b in the figure below. Constraints 1≤a<b≤15a and b are integers.Input The input is given from Standard Input in the following for…

用SpectorJS调试WebGL应用

随着使用 WebGL 构建的体验不断涌现&#xff0c;以及 WebVR/AR 领域的所有改进&#xff0c;拥有高效的调试工具变得至关重要。 无论你是刚刚起步还是已经是使用 WebGL 开发 3D 应用程序的经验丰富的开发人员&#xff0c;都可能知道工具对于生产力的重要性。 在寻找此类工具时&…

【开发环境】JRE 裁剪 ① ( 裁剪 bin 目录下的 dll 动态库文件 )

文章目录一、JRE 裁剪二、裁剪 bin 目录下的 dll 动态库文件参考博客 : 精简jre1.8精简jre步骤裁剪JRE(嵌入式设备的java环境移植) 资源下载地址 : https://download.csdn.net/download/han1202012/87388400 一、JRE 裁剪 在 【IntelliJ IDEA】使用 exe4j 生成 jre jar 可执…