Promise async await

news2024/11/20 7:17:09

简介:回调

  • JS会提供很多函数,允许异步行为。换句话说,现在开始执行的行为。但它们会在稍后完成。
  • 异步执行某项功能的函数应该提供一个 callback 参数用于在相应事件完成时调用。
  • 处理Error
    • 加载成功时,它会调用 callback(null, xxx),否则调用 callback(error),这种被称为Error优先回调风格。
    • 约定:
      • callback 的第一个参数是为 error 而保留的。一旦出现 error,callback(err) 就会被调用。
      • 第二个参数(和下一个参数,如果需要的话)用于成功的结果,此时 callback(null, result1, result2…) 就会被调用。
    • 单一的 callback 函数可以同时具有报告 error 和传递返回结果的作用。
  • 但对于一个接一个的多个异步行为,随着调用嵌套的增加,代码层次变得更深,维护难度也随之增加,尤其是我们使用的是可能包含了很多循环和条件语句的真实代码,这些被称为“回调地狱”或“厄运金字塔”。
  • 有其他的方法可以避免此类金字塔,最好的方法之一就是promise

Promise

  • Promise是将生产者代码和消费者代码连接在一起的一个特殊JS对象,是异步编程的一种解决方案

  • 构造器语法:

    let promise = new Promise(function(resolve, reject) {
      if (/* 异步操作成功 */){
        resolve(value);
      } else {
        reject(error);
      }
    });
    
  • 传递给 new Promise 的函数被称为 executor,当 new Promise 被创建,executor 会自动运行

  • 它的参数 resolvereject 是由JS自身提供的回调,代码仅在 executor 的内部。当 executor 获得了结果,无论是早还是晚都没关系,它应该调用以下回调之一:

    • resolve(value):任务成功完成并带有结果value
    • reject(error):如果出现了errorerror即为error对象
  • executor 只能调用一个 resolve一个 reject,任何状态的更改都是最终的。并且,resolve/reject 只需要一个参数(或不包含任何参数)

  • executor 通常是异步执行某些操作,并在一段时间后调用 resolve/reject,但这不是必须的,我们可以立即调用 resolvereject

  • promise 对象具有以下内部属性

    • state :最初是 "pending"
      • resolve 被调用时变为 "fulfilled"
      • reject 被调用时变为 "rejected"
    • result:最初是 undefined
      • resolve(value) 被调用时变为 value
      • reject(error) 被调用时变为 error
    • 与最初的 pending promise 相反,一个 resolvedrejectedpromise 都会被称为 settled
      在这里插入图片描述
  • stateresult 属性都是内部的,无法直接访问它们,但我们可以对它们使用 .then/.catch/.finally 方法

  • 消费者:then, catch

    • .then语法:

      promise.then(
        function(result) { /* handle a successful result */ },
        function(error) { /* handle an error */ }
      );
      
      • .then 的第一个参数是一个函数,在 promise resolved 且接收到结果后执行
      • .then 的第二个参数也是一个函数,在 promise rejected 且接收到 error 信息后执行
    • 只对成功完成的情况感兴趣,可以只为 .then 提供一个函数参数

    • 只对 error 感兴趣,可以使用 null 作为第一个参数:.then(null, f),或者也可以使用 .catch(f)

  • 简单的例子:

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 中也有 finally,调用 .finally(fn) 类似于 .then(f, f),因为当 promise settled 时 f 就会执行:无论 promise 被 resolve 还是 reject。finally 的功能是设置一个处理程序在前面的操作完成后,执行清理/终结。

  • PS:finally(f) 并不完全是 then(f, f) 的别名

    • finally 没有参数
    • finally 将结果或 error “传递”给下一个合适的处理程序
      • 成功就传递给下一个then
      • 失败就传递给下一个catch
    • finally 也不应该返回任何内容,如果它返回了会默认被忽略
  • 基于回调的好处:

    • promise允许我们按照自然顺序进行编码;而callback就必须要知道如何处理结果
    • promise可以多次调用.then;而callback只能有一个回调
  • 常见写法:

    new Promise(请求1)
        .then(请求2(请求结果1))
        .then(请求3(请求结果2))
        .then(请求4(请求结果3))
        .then(请求5(请求结果4))
        .catch(处理异常(异常信息))
    

使用promise进行错误处理

  • 当一个promisereject时,将移交到最近的rejection处理程序

  • .catch 处理 promise 中的各种 error:在 reject() 调用中的,或者在处理程序中抛出的 error

  • 如果给定 .then 的第二个参数(即 error 处理程序),那么 .then 也会以相同的方式捕获 error

  • 未处理的rejection

    new Promise(function() {
      noSuchFunction(); // 这里出现 error(没有这个函数)
    })
      .then(() => {
        // 一个或多个成功的 promise 处理程序
      }); // 尾端没有 .catch!
    
    • 如果出现了一个 error,并且在这没有 .catch,那么 unhandledrejection 处理程序就会被触发,并获取具有 error 相关信息的 event 对象,所以我们就能做一些后续处理了

      window.addEventListener('unhandledrejection', function(event) {
        // 这个事件对象有两个特殊的属性:
        alert(event.promise); // [object Promise] —— 生成该全局 error 的 promise
        alert(event.reason); // Error: Whoops! —— 未处理的 error 对象
      });
      
      new Promise(function() {
        throw new Error("Whoops!");
      }); // 没有用来处理 error 的 catch
      
  • 例子 .catch会被触发吗:

    new Promise(function(resolve, reject) {
      setTimeout(() => {
        throw new Error("Whoops!");
      }, 1000);
    }).catch(alert);
    
    • 不一定会被触发。函数代码周围有个隐式的 try..catch,所有同步错误都会得到处理。但是这里的错误并不是在 executor 运行时生成的,而是在稍后生成的,因此,promise 无法处理它。

Promise API

Promise.all

  • 并行执行多个 promise,并等待所有 promise 都准备就绪

  • 使用场景:一些游戏类的素材比较多的应用,打开网页时,预先加载需要用到的各种资源如图片、flash以及各种静态文件。所有的都加载完后,我们再进行页面的初始化

  • Promise.all 接受一个可迭代对象(通常是一个数组项为 promise 的数组),并返回一个新的 promise

  • 例子:

    Promise.all([
      new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
      new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
      new Promise(resolve => setTimeout(() => resolve(3), 1000))  // 3
    ]).then(alert); // 1,2,3 当上面这些 promise 准备好时:每个 promise 都贡献了数组中的一个元素
    
    • 结果数组中元素的顺序与其在源 promise 中的顺序相同。即使第一个 promise 花费了最长的时间才 resolve,但它仍是结果数组中的第一个
  • 任意一个 promise 被 reject,由 Promise.all 返回的 promise 就会立即 reject,并且带有的就是这个 error

  • Promise.all(...) 接受含有 promise 项的可迭代对象(大多数情况下是数组)作为参数,但如果这些对象中的任何一个不是 promise,那么它将被按原样传递给结果数组

    Promise.all([
      new Promise((resolve, reject) => {
        setTimeout(() => resolve(1), 1000)
      }),
      2,
      3
    ]).then(alert); // 1, 2, 3
    

Promise.allSettled

  • 最近新增的特性,旧浏览器可能需要polyfills
  • Promise.allSettled 等待所有的 promise 都被 settle,无论结果如何,结果数组具有:
    • {status:"fulfilled", value:result} 对于成功的响应
    • {status:"rejected", reason:error} 对于 error
  • 例如,我们想要获取(fetch)多个用户的信息。即使其中一个请求失败,我们仍然对其他的感兴趣

Promise.race

  • 只等待第一个settledpromise并获取其结果或error

  • 例子:

    let promise = Promise.race(iterable);
    Promise.race([
      new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
      new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000)),
      new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
    ]).then(alert); // 1
    
    • 第一个 promise 最快,所以它变成了结果,其他的result/error会被忽略
  • 谁跑得快,以谁为准执行回调

  • 使用场景:可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作

     //请求某个图片资源
        function requestImg(){
            var p = new Promise((resolve, reject) => {
                var img = new Image();
                img.onload = function(){
                    resolve(img);
                }
                img.src = '图片的路径';
            });
            return p;
        }
        //延时函数,用于给请求计时
        function timeout(){
            var p = new Promise((resolve, reject) => {
                setTimeout(() => {
                    reject('图片请求超时');
                }, 5000);
            });
            return p;
        }
        Promise.race([requestImg(), timeout()]).then((data) =>{
            console.log(data);
        }).catch((err) => {
            console.log(err);
        });
    
    • requestImg函数会异步请求一张图片,把地址写为"图片的路径",所以肯定是无法成功请求到的。timeout函数是一个延时5秒的异步操作。我们把这两个返回Promise对象的函数放进race,于是它俩就会赛跑。
    • 如果5秒之内图片请求成功了,那么进入then方法,执行正常的流程。
    • 如果5秒钟图片还未成功返回,那么timeout就跑赢了,则进入catch,报出“图片请求超时”的信息

Promise.any

  • Promise.race类似,区别在于它只等待第一个 fulfilled 的 promise,并将这个 fulfilled 的 promise 返回
  • 如果给出的 promise 都 rejected,那么返回的 promise 会带有 AggregateError —— 一个特殊的 error 对象,在其 errors 属性中存储着所有 promise error

Promise.resolve

  • 给定 value 创建一个resolvedpromise

Promise.reject

  • 给定 error 创建一个 rejected promise

Promisification

  • 将一个接受回调的函数转换为一个返回 promise 的函数
  • Promisification 是一种很好的方法,特别是在使用 async/await 的时候,但不是回调的完全替代
  • 一个promise可能只有一个结果,但从技术上讲,一个回调可能被调用很多次。因此,promisification 适用于调用一次回调的函数,进一步的调用将被忽略。

微任务

  • promise 的处理程序 .then.catch.finally 都是异步的。即便一个 promise 立即被 resolve,.then.catch.finally 下面 的代码也会在这些处理程序之前被执行。

    let promise = Promise.resolve();
    promise.then(() => alert("promise done!"));
    alert("code finished"); // 这个 alert 先显示
    
  • 异步任务需要适当的管理,ECMA 标准规定了一个内部队列 PromiseJobs,通常被称为微任务队列。当一个 promise 准备就绪时,它的 .then/catch/finally 处理程序就会被放入队列中,但是它们不会立即被执行。当 JavaScript 引擎执行完当前的代码,它会从队列中获取任务并执行它。

  • 如果有一个包含多个 .then/catch/finally 的链,那么它们中的每一个都是异步执行的。也就是说,它会首先进入队列,然后在当前代码执行完成并且先前排队的处理程序都完成时才会被执行。

  • 想让 code finishedpromise done 之后出现,就要把.then放入队列里

    Promise.resolve()
      .then(() => alert("promise done!"))
      .then(() => alert("code finished"));
    
  • 现在可以解释 JavaScript 是如何发现未处理的 rejection 的。如果一个 promise 的 error 未被在微任务队列的末尾进行处理,则会出现“未处理的 rejection”

  • 正常来说,我们会在 promise 链上添加 .catch 来处理 error:

    let promise = Promise.reject(new Error("Promise Failed!"));
    promise.catch(err => alert('caught'));
    
    // 不会运行:error 已经被处理
    window.addEventListener('unhandledrejection', event => alert(event.reason));
    
  • 忘记添加 .catch,那么,微任务队列清空后,JavaScript 引擎会触发下面这事件:

    let promise = Promise.reject(new Error("Promise Failed!"));
    
    // Promise Failed!
    window.addEventListener('unhandledrejection', event => alert(event.reason));
    
  • 如果迟一点再处理:

    let promise = Promise.reject(new Error("Promise Failed!"));
    setTimeout(() => promise.catch(err => alert('caught')), 1000);
    
    // Error: Promise Failed!
    window.addEventListener('unhandledrejection', event => alert(event.reason));
    
    • 我们会先看到 Promise Failed!,然后才是 caught
    • 当微任务队列中的任务都完成时,才会生成 unhandledrejection:引擎会检查 promise,如果 promise 中的任意一个出现 rejected状态,unhandledrejection 事件就会被触发
    • 在上面这个例子中,被添加到 setTimeout 中的 .catch 也会被触发,只是会在 unhandledrejection 事件出现之后才会被触发,所以它并没有改变什么(没有发挥作用)

async / await

  • async / await 是以更舒适的方式使用 promise 的一种特殊语法

  • async 可以被放置在一个函数前面,即这个函数总是返回一个 promise,其他值将自动被包装在一个 resolved 的 promise 中

  • await只在 async 函数内工作,它让 JavaScript 引擎等待直到 promise 完成(settle)并返回结果。如果有 error,就会抛出异常,就像那里调用了 throw error 一样

  • await 实际上会暂停函数的执行,直到 promise 状态变为 settled,然后以 promise 的结果继续执行。这个行为不会耗费任何 CPU 资源,因为 JavaScript 引擎可以同时处理其他任务:执行其他脚本,处理事件等

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

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

相关文章

Z Potentials | 星爵,他的征途不止向量数据库

纵观过去几十年的科技发展史,每一代新的技术架构的出现往往都伴随着新的数据范式的出现,也催生了多家百亿到千亿美金数据平台的诞生。如果说 2023 年科技领域的关键词是 LLM,那么数据库领域的关键词一定非向量数据库莫属。向量数据库是一种专…

我们是如何测试人工智能产品的

在当今数字化时代,人工智能(AI)技术已经成为我们生活中不可或缺的一部分。然而,要构建出可信赖的AI系统并非易事。这需要我们不仅深入理解人工智能的核心原理,还需要将这些理论知识应用到实际场景中。 为了帮助大家系…

一个不错的空间视频收集论坛

该网站收录了来自世界各地的空间视频、空间照片和全景照片,以突出令人惊叹的 Apple Vision Pro 的功能。 网站地址:

Java 客户端向服务端上传文件(TCP通信)

一、实验内容 编写一个客户端向服务端上传文件的程序,要求使用TCP通信的的知识,完成将本地机器输入的路径下的文件上传到D盘中名称为upload的文件夹中。并把客户端的IP地址加上count标识作为上传后文件的文件名,即IP(count&#…

mysql中insert … select锁范围

1、执行 insert … select 的时候,对目标表也不是锁全表,而是只锁住需要访问的资源。 例如, CREATE TABLE t (id int(11) NOT NULL AUTO_INCREMENT,c int(11) DEFAULT NULL,d int(11) DEFAULT NULL,PRIMARY KEY (id),UNIQUE KEY c (c) ) EN…

IP定位技术在金融风控中的应用研究

随着金融科技的快速发展,金融行业的风险也呈现出多样化、复杂化的特点。金融风控作为保障金融安全的重要手段,其面临的挑战也日益加剧。在这样的背景下,IP定位技术作为一种先进的信息技术手段,正逐渐成为金融风控领域的重要工具。…

精酿啤酒:原料来源的追溯与认证体系

为了确保啤酒品质的可靠性和安全性,Fendi Club啤酒建立了一套完善的原料来源追溯与认证体系。这套体系旨在确保从原料采购到生产过程的每一个环节都能得到进一步监控和管理,从而提高产品质量,降低风险。 Fendi Club啤酒对原料供应商进行严格的…

【kerberos】hadoop集群使用keytab认证的逻辑

一、背景: haoop的kerberos认证核心是org.apache.hadoop.security.UserGroupInformation类。 UserGroupInformation一般有两种:(1)apache原生的(2)cdh hdp改良过的,即cloudera改良过的。 由此衍…

Kube-Prometheus 监控Istio

推荐 Istio 多集群监控使用 Prometheus,其主要原因是基于 Prometheus 的分层联邦(Hierarchical Federation)。 通过 Istio 部署到每个集群中的 Prometheus 实例作为初始收集器,然后将数据聚合到网格层次的 Prometheus 实例上。 网…

【Web】浅聊Java反序列化之C3P0——不出网Hex字节码加载利用

目录 简介 原理分析 EXP 前文:【Web】浅聊Java反序列化之C3P0——URLClassLoader利用 简介 不出网的情况下,这个C3P0的Gadget可以和fastjson,Snake YAML , JYAML,Yamlbeans , Jackson,Blazeds,Red5, Castor等配合使用(调用setter和初始化…

【php】【mysql】 原生初级简易新闻发布系统成品代码动态网站开发网页WEB浏览器端B/S结构

【php】【mysql】 原生初级简易新闻发布系统成品代码动态网站开发网页WEB浏览器端B/S结构 一级目录二级目录三级目录 获取源码方式项目说明:项目运行环境文件包含运行截图程序代码结构图新闻首页图新闻详情图新闻列表管理图个人信息管理图登录界面新闻详情新闻发布 …

基于JavaWeb的NBA赛事信息管理系统

目 录 摘 要 I Abstract II 引 言 1 1 系统概述 3 1.1 系统开发背景及意义 3 1.2 开发环境、工具 3 1.3 相关技术 4 1.3.1 前端技术 4 1.3.2 数据库技术 4 1.4 本章小结 4 2 系统分析 5 2.1 功能需求分析 5 2.2 性能需求分析 5 2.3 本章小结 6 3 系统设计 7 3.1 功能设计 7 3.…

拼多多1000元虚拟店铺免4万保证金

众所周知拼多多现在流量非常大,虚拟也算是蓝海,想做的人大部分都被保证金拦在门外,高达4W的保证金不是每个人都能承受的,正好在当下有一个方法可以解决这个苦恼。 拼多多虚拟店铺免保证金玩法现在处于前期阶段,很多人…

如何搭建 Jenkins 自动化测试平台?

前言 在进行平台搭建前,我们首先要问自己:我需要搭建的平台的功能是什么,要实现什么目标? 在我的理解中,自动化构建平台的执行流程(目标)是: 我们将代码提交到代码托管工具上&…

Linux 关于NTP同步硬件时钟的可靠性验证

Linux关于NTP同步硬件时钟的可靠性验证 1. 常见的时钟类型1.1 系统时钟1.2 硬件时钟 2. 常见时钟同步方式2.1 ntpd服务2.1.1 推荐配置/etc/ntp.conf2.1.2 推荐配置/etc/sysconfig/ntpd 2.2 定时任务ntpdate2.3 ntp命令同步状态相关命令解读2.3.1 ntpq -pn解读2.3.2 ntpdate -u解…

【牛客】VL74 异步复位同步释放

描述 题目描述: 请使用异步复位同步释放来将输入数据a存储到寄存器中,并画图说明异步复位同步释放的机制原理 信号示意图: clk为时钟 rst_n为低电平复位 d信号输入 dout信号输出 波形示意图: 输入描述: clk为时…

STM32 SDRAM知识点

1.SDRAM和SRAM的区别 SRAM不需要刷新电路即能保存它内部存储的数据。而SDRAM(Dynamic Random Access Memory)每隔一段时间,要刷新充电一次,否则内部的数据即会消失,因此SRAM具有较高的性能,但是SRAM也有它…

外贸常用的出口认证 | 全球外贸数据服务平台 | 箱讯科技

出口认证是一种贸易信任背书,对许多外贸从业者而言,产品的出口认证和当前的国际贸易环境一样复杂多变,不同的目标市场、不同的产品类别,所需要的认证及标准也不同。 国际认证 01 IECEE-CB IECEE-CB体系的中文含义是“关于电工产品测试证书的相互认可体…

【❤️算法笔记❤️】-每日一刷-19、删除链表的倒数第 N个结点

文章目录 题目思路解答 题目 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 输入:head [1,2,3,4,5], n 2 输出:[1,2,3,5]示例 2: 输入:head [1], n 1 输出:[]示例 3&…

QT中的信号和槽

信号和槽概述 在 Qt 中,用户和控件的每次交互过程称为⼀个事件。比如 “用户点击按钮” 是⼀个事件,“用户关闭窗口” 也是⼀个事件。每个事件都会发出⼀个信号,例如用户点击按钮会发出 “按钮被点击” 的信号,用户关闭窗口会发出…