Promise

1.Promise的前置知识

  • 进程(厂房)

    • 程序的运行环境
  • 线程(工人)

  • 线程是实际进行运算的东西

  • 同步

    • 通常情况代码都是自上向下一行一行执行的
    • 前边的代码不执行后边的代码也不会执行
    • 同步的代码执行会出现阻塞的情况
    • 一行代码执行慢会影响到整个程序的执行
  • 解决同步的问题:

    • java python

      • 通过多线程来解决,但是一般消耗资源比较多
    • node.js

      • 通过异步方式来解决

        我们可以这么理解:客人就好比我们请求的数据,服务员就好比客户端,厨师就好比服务器,我们现在客人点菜,服务员接收到菜的名称信息,给厨师说,厨师开始做,厨师在做的时候,客人一直等,不能干其他的事情,这就是同步,只能干一件事,我们现在利用异步的方式,可以让客人在课桌上等着菜来,也不影响服务员接收下一个客人的点菜,这样就可以很好的处理同步所带来的堵塞问题

  • 异步

    • 一段代码的执行不会影响到其他的程序
    • 异步的问题:
  • 异步的代码无法通过return来设置返回值

  • 特点:

    1. 不会阻塞其他代码的执行

    2. 需要通过回调函数来返回结果

      function sum(a, b, cb) {
      setTimeout(() => {
      cb(a + b) //调用箭头函数,把结果作为回调函数的参数
      }, 1000)
      } sum(123, 456, (result)=>{
      console.log(result)
      })
  • 基于回调函数的异步带来的问题

    1. 代码的可读性差

    2. 可调试性差(造成回调地狱)

      sum(123, 456, (result)=>{
      sum(result, 7, (result)=>{
      sum(result, 8, result => {
      sum(result, 9, result => {
      sum(result, 10, result => {
      console.log(result)
      })
      })
      })
      })
      })
  • 解决问题:

    • 需要一个东西,可以代替回调函数来给我们返回结果
    • Promise横空出世
      • Promise是一个可以用来存储数据的对象

        • Promise存储数据的方式比较特殊,这种特殊的方式使得Promise可以用来存储异步调用的数据

2.Promise介绍

异步调用必须要通过回调函数来返回数据,当我们进行一些复杂的调用时,会出现回调地狱

问题:

​ 异步必须通过回调函数来返回结果,回调函数增加就不容易处理

  • Promise

    • Promise可以帮助我们解决异步中的回调函数的问题
    • Promise就是一个用来存储数据的容器
      • 它拥有着一套特殊的存储数据的方式
      • 这个方式使得它里面可以存储异步调用的结果
  1. 创建Promise

    1. 创建Promise时,构造函数中需要一个函数作为参数

    2. Promise构造函数的回调函数,它会在创建Promise时调用,调用时会有两个参数传递进去

      const promise = new Promise((resolve, reject)=>{
      // resolve 和 reject 是两个函数,通过这两个函数可以向Promise中存储数据
      // resolve 在执行正常的时候存储数据, reject 是在执行错误的时候存储数据
      resolve('我是正常执行的时候调用的')
      reject('我是错误执行的时候调用的')
      //通过函数来访问Promise中添加数据,好处就是可以用来添加异步调用的数据
      setTimeout(()=>{
      resolve('异步中调用数据')
      },2000)
      throw new Error('出错了,调用的是reject')
      })
  2. 从Promise中读取数据

    1. 可以通过Promise的实例方法then来读取Promise中存储的数据

    2. then需要两个回调作为参数,回调函数来获取Promise中的数据

      1. 通过resolve存储的数据,会调用第一函数返回,可以在第一个函数中编写处理数据的代码

      2. 通过reject存储数据或者出现异常时,会调用第二个函数返回,可以在第二个函数中编写处理异常的代码

        promise.then((result)=>{
        console.log('1',result)
        },(reson)=>{
        console.log('2',reason)
        })
  3. Promise中维护了两个隐藏属性:

    1. PromiseResult

      1. 用来存储数据
    2. PromiseState
      1. 记录Promise的状态(三种状态)

        1. pending(进行中)
        2. fulfilled(完成)通过resolve存储数据时
        3. rejected(拒绝,出错了)出错了或通过reject存储数据时
      2. state只能修改一次,修改以后永远不会在变
    3. 流程:
      1. 当Promise创建时,PromiseState初始值为pending

        1. 当通过resolve存储数据时 PromiseState 变为fulfilled(完成)

          1. PromiseResult变为存储的数据
        2. 当通过reject存储数据或出错时 Promise 变为rejected(拒绝)
          1. PromiseResult变为存储的数据 或 异常对象
      2. 当我们通过then读取数据时,相当于为Promise设置了回调函数
        1. 如果PromiseState变为fulfilled,则调用then的第一个回调函数来返回数据
        2. 如果PromiseState变为rejected。则调用then的第二个回调函数来返回数据
    const promise2 = new Promise((resolve, reject) => {
    resolve("哈哈")
    }) // console.log(promise2)
    promise2.then(result => {
    console.log(result)
    }, reason => {
    console.log("出错了")
    })
  4. catch()用法和then类似,但是只需要一个回调函数作为参数

    1. catch() 中的回调只会在Promise被拒绝时才会调用

    2. catch() 相当于 then(null, reason=>{})

    3. catch() 就是一个专门处理Promise异常的方法

      promise2.catch(reason => {
      console.log(222222)
      })
  5. finally()

    1. 无论是正常存储数据还是出现异常了,finally总会执行

    2. 但是finally的回调函数中不会接收到数据

    3. finally()通常用来编写一些无论成功与否都要执行的代码

      promise2.finally(()=>{
      console.log("没有什么能够阻挡我执行的!")
      })

3.Promise详解

3.1Promise用法

Promise就是一个用来存储数据对象,但是由于Promise存取的方式的特殊,所以可以直接将异步调用的结果存储到Promise中

function sum(a, b) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(a + b)
}, 1000)
})
}
//回调地狱式写法:
sum(123, 456).then(result => {
sum(result, 7).then(result =>{
sum(result, 8).then(result => {
console.log(result)
})
})
})
//promise写法:
sum(123, 456)
.then(result => result + 7)
.then(result => result + 8)
.then(result => console.log(result))

下来我们就解释一下为什么是这种链式调用的形式:

​ promise中的then方法会返回一个新的Promise,而我们接收并且输出的是Promise的PromiseResult的值,就像这样:then (return new Promise()),

Promise中会存储回调函数的返回值,当前的参数是上一个链式调用的返回值

promise
.then(result => {
console.log("回调函数", result)
return "会作为下个then的参数"
})
.then(result => {
console.log("第二个then", result) //第二个then,会作为下个then的参数
return "taotao真快乐"
})
.then(result => {
console.log(result) //taotao真快乐
})

promise中的

  1. then (return new Promise())
  2. catch
  3. 这三个方法都会返回一个新的Promise, Promise中会存储回调函数的返回值
  4. finally
    1. finally的返回值,不会存储到新的Promise中
  5. 对Promise进行链式调用时,后面的方法(then和catch)读取的上一步的执行结果
    1. 如果上一步执行结果不是当前想要的结果,则跳过当前的方法,执行下一个方法
    2. 一般都把catch写到最后,只写一个,最后统一处理异常
    3. 当Promise出现异常时,而整个调用链中没有catch,则异常会向外抛出

3.2Promise静态方法

  1. Promise.resolve() 创建一个立即完成的Promise

    1. Promise.resolve('成功调用时的数据').then(
      (result)=>{
      console.log(1111)
      })
      //相当于
      new Promise((resolve, reject)=>{
      resolve('成功调用时的数据')
      }).then(result=>{
      console.log(1111)
      })
  2. Promise.reject() 创建一个立即拒绝的Promise

    1. Promise.reject('错误')
  3. Promise.all([...]) 同时返回多个Promise的执行结果

    1. 其中有一个报错,就返回错误

    2. function sum(a, b){
      return new Promise((resolve, reject)=>{
      setTimeout(()=>{
      resolve(a + b)
      },1000)
      })
      }
      //传递一个可迭代对象(类数组)
      Promise.all(
      sum(111, 222),
      Promise.reject("哈哈"),
      sum(222, 333),
      sum(333, 444)
      ).then((result)=>{
      console.log(result) //[ 579, 11, 77 ]
      }).catch ((reason)=>{
      console.log(reason) //'哈哈'
      })
  4. Promise.allSettled([...]) 同时返回多个Promise的执行结果(无论成功或失败)

    1. {status: 'fulfilled', value: 579}

    2. {status: 'rejected', reason: '哈哈'}

    3. Promise.allSettled([
      sum(123, 456),
      sum(5, 6),
      Promise.reject("哈哈"),
      sum(33, 44)
      ]).then(r => {
      console.log(r)
      }) //返回的结果如下:
      [
      { status: 'fulfilled', value: 579 },
      { status: 'fulfilled', value: 11 },
      { status: 'rejected', reason: '哈哈' },
      { status: 'fulfilled', value: 77 }
      ]
  5. Promise.race([...]) 返回执行最快的Promise(不考虑对错)

    1. Promise.race([
      Promise.reject(1111),
      sum(123, 456),
      sum(5, 6),
      sum(33, 44)
      ]).then(r => {
      console.log(r)
      }).catch(r=>{
      console.log(r)
      })
      //执行结果如下
      1111
      Promise.reject(1111),不用等定时器执行结束,直接就调用
  6. Promise.any([...]) 返回执行最快的完成的Promise

    1. Promise.any([
      Promise.reject(1111),
      Promise.reject(2222),
      Promise.reject(3333),
      ]).then(r => {
      console.log(r)
      }).catch(r => {
      console.log("错误", r)
      })

Promise知一二的更多相关文章

  1. 浅谈JavaScript、ES5、ES6

    // http://es6.ruanyifeng.com/#docs/intro (ES6 文档) 什么是JavaScript JavaScript一种动态类型.弱类型.基于原型的客户端脚本语言,用来 ...

  2. 程序员编程艺术第三十六~三十七章、搜索智能提示suggestion,附近点搜索

    第三十六~三十七章.搜索智能提示suggestion,附近地点搜索 作者:July.致谢:caopengcs.胡果果.时间:二零一三年九月七日. 题记 写博的近三年,整理了太多太多的笔试面试题,如微软 ...

  3. ChartDirector应用笔记(一)

    ChartDirector介绍 ChartDirector是一款小巧精细的商业图表库.其适用的语言范围非常广泛,包括.Net, Java, Asp, VB, PHP, Python, Ruby, C+ ...

  4. trie树(前缀树)

    问题描述:   Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优 ...

  5. Codeforces Round #258 (Div. 2)[ABCD]

    Codeforces Round #258 (Div. 2)[ABCD] ACM 题目地址:Codeforces Round #258 (Div. 2) A - Game With Sticks 题意 ...

  6. H5、React Native、Native应用对比分析

    每日更新关注:http://weibo.com/hanjunqiang  新浪微博!iOS开发者交流QQ群: 446310206 "存在即合理".凡是存在的,都是合乎规律的.任何新 ...

  7. 从Trie树(字典树)谈到后缀树

    转:http://blog.csdn.net/v_july_v/article/details/6897097 引言 常关注本blog的读者朋友想必看过此篇文章:从B树.B+树.B*树谈到R 树,这次 ...

  8. H5、React Native、Native性能区别选择

    “存在即合理”.凡是存在的,都是合乎规律的.任何新事物的产生总要的它的道理:任何新事物的发展总是有着取代旧事物的能力.React Native来的正是时候,一则是因为H5发展到一定程度的受限:二则是移 ...

  9. 海量数据处理之Tire树(字典树)

    参考博文:http://blog.csdn.net/v_july_v/article/details/6897097 第一部分.Trie树 1.1.什么是Trie树 Trie树,即字典树,又称单词查找 ...

  10. Unity3D 记第二次面试

    2014-03-10 忍不住投递了几份简历大概有20个,总共收到面试电话2个,十分之一.一个是11号下午4点面试另一个是12号下午3点面试(后来没去至于原因下面有)12号没去,为什么?因为招聘要求“精 ...

随机推荐

  1. Helm包管理

    Helm Kubernetes 包管理工具 Helm 可以帮助我们管理 Kubernetes 应用程序 - Helm Charts 可以定义.安装和升级复杂的 Kubernetes 应用程序,Char ...

  2. RabbitMQ原理和架构图解(附6大工作模式)

    为什么要使用RabbitMQ? 1.解耦 系统A在代码中直接调用系统B和系统C的代码,如果将来D系统接入,系统A还需要修改代码,过于麻烦. 2.异步 将消息写入消息队列,非必要的业务逻辑以异步的方式运 ...

  3. PAT (Basic Level) Practice 1030 完美数列 分数 25

    给定一个正整数数列,和正整数 p,设这个数列中的最大值是 M,最小值是 m,如果 M≤mp,则称这个数列是完美数列. 现在给定参数 p 和一些正整数,请你从中选择尽可能多的数构成一个完美数列. 输入格 ...

  4. 大华海康NVR录像JAVA下载及WEB播放

    近期在处理一个将NVR录像机上的录像下载到服务器并通过浏览器播放的需求. 梳理记录下过程,做个备忘,同时遇到的一些细节问题解决,也供需要的同学参考. 需求比较简单,就是把指定时间段的录像上传到服务器保 ...

  5. MyBatis之ResultMap的association和collection标签详解

    一.前言 MyBatis 创建时的一个思想是:数据库不可能永远是你所想或所需的那个样子. 我们希望每个数据库都具备良好的第三范式或 BCNF 范式,可惜它们并不都是那样. 如果能有一种数据库映射模式, ...

  6. hibernate validation 手动参数校验 不经过spring

    /** * 校验工具类 * @author wdmcygah * */ public class ValidationUtils { private static Validator validato ...

  7. Java云原生崛起微服务框架Quarkus入门实践

    @ 目录 概述 定义 GraalVM简介 为何使用 特性 官方性能 实战 入门示例 步骤 安装GraalVM 创建quarkus工程 Idea导入项目 Idea运行和调试 打包成普通的Jar 打包成依 ...

  8. System.IO.FileSystemWatcher的坑

    System.IO命名空间下面有一个FileSystemWatcher,这个东西可以实现文件变动的提醒.需要监控文件夹变化(比如FTP服务器)的情形非常适用. 需要监控文件新建时,我们可以这么写: _ ...

  9. docker gitlab迁移 备份 部署 搭建以及各种问题

    当前环境 服务器A 服务器B ubuntu docker gitlab(版本一致) docker安装gitlab 由于考虑到gitlab 包含了⾃身的nginx.数据库.端⼝占⽤等等因数,这⾥使⽤的是 ...

  10. 后端框架学习3------SpringMVC

    springMVC学习笔记 官方文档地址:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html# ...