es6 异步处理之 Promise学习总结

简介: es6 异步处理之 Promise学习总结
    =========================事件循环==================
    先看以下的例子:
    例1:
    console.log("a");
    setTimeout(() => {
        console.log("b");
    }, 0)
    console.log("c");
    // 以上的结果是 先输出 a, c, b
    // 然后看下面的例子:
    console.log("a");
    setTimeout(() => {
        console.log("b");
    }, 0)
    for(let i = 0; i < 1000; i ++){
        console.log("c")
    }
    // 以上的结果是 a 1000个c  最后是 b
    问:为什么总都是b在最后呢?
    事件回顾:
    JS运行的环境称之为宿主环境。
    执行栈:call stack , 一个数据结构, 用于存放各种函数的执行环境,每一个函数执行之前,
    它的相关信息会加入到执行栈。 函数调用之前, 创建执行环境, 然后加入到执行栈; 函数调用之后,销毁执行环境
    JS引擎执行的都是栈的最顶部,执行完后,顶部的执行上下文会销毁(出栈),
    调用函数之前一定要先入栈(创建一个对应的上下文),执行完后出栈,销毁对应的上下文
    异步函数: 某些函数不会立即执行,需要等到某个时机到达后才会执行,这样的函数称为
    异步函数,比如:事件处理函数,setTimout,setTimeItervel等。异步函数的执行时机,会被宿主环境控制。
    浏览器宿主环境中包含5个线程:
    1. JS引擎: 负责执行栈的最顶部代码
    2. GUI线程: 负责渲染页面
    3. 事件监听线程: 负责监听各种事件
    4. 计时线程: 负责计时, 如setTimeOut, setTimeInterval等
    5. 网络线程: 负责网络通信, 如 ajax, axios等
    当上面的线程发生某些事情,如果该线程发现,这件事情有处理程序,他会将该处理程序加入
    到一个叫做事件队列的内存中。 当JS引擎发现,执行栈中已经没有了任何内容后,会将事件队列中
    的第一个函数加入到执行栈中执行。
    JS引擎对事件队列的取出方式,以及与宿主环境的配合,称之为事件循环。
    事件队列在不同的宿主环境中有所差异,大部分宿主环境会将事件队列进行细分。
    在浏览器中,事件队列分为两种:
    宏队列: macroTask, 计时器结束的回调,事件回调,http回调等绝大部分异步函数进入宏队列
    微队列: mutationObserver, Promise产生的回调进入微队列
    mutationObserver: 用于监听dom里面属性或者结构发生变化时,dom发生变化。
    当执行栈清空时, JS引擎首先会将微队列中的所有任务依次执行结束,如果没有微队列的任务,则执行宏队列里面的任务
    =================es6异步处理 Promise=================
    事件和回调函数的缺陷:
    我们习惯于使用传统的回调或事件处理来解决回调
    事件: 某个对象的属性是一个函数,当发生某一事件时,运行该函数
    dom.onclick = function(){}
    回调: 运行某个函数以实现某个功能的时候,传入一个函数作为参数,当发生某件事的时候,会运行该函数
    dom.addEventLinster("click",function(){})
    本质上,事件和回调并没有本质的区别,只是函数放置的位置不同而且。
    该模式主要面临以下问题:
    1. 回调地狱:某个异步操作需要等待之前的异步操作完成,无论用回调还是事件,都会陷入不断的嵌套
    2. 异步之间的联系: 某个异步操作要等待多个异步操作的结果,对这种联系的处理,会让代码的复杂度剧增
    异步处理的通用模型
    ES 官方参考了大量的异步场景,总结一套异步的通过模型,该模型可以覆盖几乎所有的异步场景,甚至同步场景
    值得注意的是,为了兼容旧系统,ES6 并不打算抛弃过去的做法,只是基于该模型推出的一个权限的 API, 使用该APi, 让异步处理更加的简洁优雅
    理解该API, 最重要的是,理解他的api
    1. ES6 将某一件可能发生异步操作的事情,可以分为两个阶段: unsettled 和 settle
    unsettled: 未决阶段,表示事情还在进行前提的处理,并没有发生通向结果的那件事;
    settled: 已决阶段, 事情已经有了一个结果,不管这个结果是好是坏,整件事情无法逆转;
    事情总是从 未决阶段 逐步发展到 已决阶段的。 并且,未决阶段拥有控制何时通向已决阶段的能力
   2. ES6 将事情划分为三种状态: pending, resolved rejected
    pending: 挂起,处于未决阶段,则表示这件事情还在挂起(最终的结果还没有出来)
    resolved: 已处理, 已决阶段的一种状态,表示整件事情出现了结果,并且是正常逻辑进行下去的结果
    rejected: 已拒绝, 已决阶段的一种状态,表示整件事情出现结果,并不是一个正常的结果,错误的结果
   既然未决阶段有权决定事情的走向,因此,未决阶段可以决定事情最终的状态!
   我们 把事情变为resolved状态的过程叫做:resolve,推向该状态时候,可能还会传递一些数据。
   我们 把事情变为rejected状态的过程叫做:rejected,推向该状态时候,可能还会传递一些数据,一些错误的信息。
   无论是哪个阶段,过程都是不可逆的
   3. 当事情的处理到达已决状态, 不同的状态决定不同的处理
      resolved状态: 这是一个正常的已决的状态,后续处理表示未thenable
      rejected状态:这个一个非正常的已决的状态,后续处理表示未catchable
      后续处理可能有多个,因此会形成作业队列,这些后续处理按照顺序,当状态到达后依次执行
  Promise API:
  promise 不是消除回调,而是将回调用两种状态来返回
  使用方法:
    const pro = new Promise((resolve, reject) => {
        // 未决阶段,也可以理解为等待阶段,异步之前做的事情,代码在这里写
        // 通过调用resolve函数将Promise推向已决阶段的resolve状态(成功)
        // 通过调用reject函数将Promise推向已经阶段的reject状态(失败)
        // resolve 和rejecte 均可以传递最多一个参数,表示推送状态的数据
    })
    pro.then(data => {
        // 这是thenable 函数, 如果当前的Promise已经是resolved状态,该函数会立即执行, 
        // 如果当前是为决状态,则会加入到作业队列,等待到达resolved状态后执行
        // data为resolved 的状态数据
    }, err => {
         // 这是catchable 函数, 如果当前的Promise已经是rejected状态,该函数会立即执行
        // 如果当前是为决状态,则会加入到作业队列,等待到达rejected状态后执行
        // err 为rejected 的状态数据
    })
    细节:
    1. 未决阶段的函数的代码是同步代码的,会立即执行
    2. thenable 和catchable 函数是异步的,就是放到立即执行,但是必须需要等到同步代码执行完后,才会执行,并且是加入的是微队列里面
    3. pro.then() 可以单独thenable的函数, 也可单独添加catchable的函数, 如 pro.catch();
    4.  在未决状态中发生错误或者抛出错误,会将错误推向reject,并且会被catchable捕获
    5. 一旦状态推向已决,状态不可以改变
    6. promise并没有消除回调, 只是让回调变的可控
    =======================Promise 串联======================
    当后续的promise需要用到之前promise产生的结果;
    Promise 无论then方法,还是catch方法, 返回的是一个全新的Promise对象,状态满足下列规则:
     1. 返回的Promise对象如果是挂起状态(未决),新的Promise的状态也是挂起状态
     2. 如果当前的Promise是已决状态, 会运行后续的函数,并将后续处理函数的结果(返回值)
      作为resolved状态数据,会应用奥新的Promise中; 如果后续处理函数发生错误,则把返回值当作
      rejected状态数据,应用到新的Promise中(后续的Promise,需要等到前面的promise已决)
      如果前面的Promise的后续处理,返回的是一个Promise, 那么后面的Promise的状态和前面的状态信息保持一致
       const pro = new Promise((resolve, reject) => {
        resolve(1);
    });
    const pro1 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(3);
        }, 3000)
    });
    pro.then(result => {
        console.log("第一个promise的状态")
        console.log(result) // 1
        return pro1;
    }).then(result => {
        console.log(result) // 3 下面是undefined,是因为这里没有返回
    }).then(result => {
        console.log(result) //undefined
    })
    // 输出结果 3 和 undefined 在3秒后打印
    Promise的其他api
    原型成员(实例成员):
    then: 注册一个后续处理函数,当Promise为resolved状态时运行该函数
    catch: 注册一个后续处理函数, 当Promise为rejected状态时运行该函数
    finally:[es2018] 注册一个后续处理函数(无参),当Promise为已决时运行该函数
    例如:
    const pro = new Promise((resolve, reject) => {
        resolve(1)
    });
    pro.finally(() => {
        console.log("第一次finally的执行");
    })
    pro.then(res => {
        console.log(res, "已决resolved得出的结果")
    })
    pro.catch(err => {
        console.log(err, "已决reject得出结果")
    })
    pro.finally(() => {
        console.log("已决第二次执行finally")
    })
    // 得出结果如下:
    // 第一次finally的执行
    // 1 已决resolved得出的结果
    // 已决第二次执行finally
    构造函数成员(静态成员)
    resolve: 该方法返回一个resolved状态的Promise,传递的数据作为状态数据;
    特殊情况:如果传递的数据是promise, 则直接返回传递的Promise对象
    例如:
    const pro = new Promise((resolve, reject) => {
        // 这里面的代码是同步代码
        resolve(1);
    })
    //  等效于
    const pro = Promise.resolve(1);
    特殊情况:
    const pro = new Promise((resolve, reject) => {
        // 这里面的代码是同步代码
        resolve(1);
    })
    const pro1 = Promise.resolve(pro);
    //  等效于
    const pro1 = pro;
    reject: 该方法返回一个rejectd状态的Promise,传递的数据作为状态数据
    例如:
    const pro = new Promise((resolve, reject) => {
        // 这里面的代码是同步代码
        reject(1);
    })
    //  等效于
    const pro = Promise.reject(1);
    all(iterable): 这个方法返回一个新的Promise对象, 该promise对象在所有promise数组中
    所有的promise都已决resolved的时候触发成功方法, 一旦有任何一个promise里面的已决rejected状态
    一行,会把错误立即返回;
    例如:
      function getRandom(min, max) {
        return Math.floor(math.getRandom() * ((max - min) + min))
    }
    const proms = [];
    for (let i = 0; i < 10; i++) {
        proms.push(new Promise((resolve, rejecct) => {
            setTimeout(() => {
                resolve(i)
            }, getRandom(1000, 5000));
        }))
    }
    // 等待所有promise完成
    Promise.all(proms).then(res => {
        console.log("所有promise 已决resolved状态后执行")
    })
    race: 有一个成功那就成功,有一个失败那就失败,返回的是一个Promise
相关文章
|
1月前
|
前端开发 JavaScript 测试技术
ES6:什么是Promise?
ES6:什么是Promise?
15 0
|
2月前
|
前端开发 小程序 JavaScript
es6读书笔记(五)Promise
es6读书笔记(五)Promise
|
5月前
|
前端开发 JavaScript
从0开始学习JavaScript--JavaScript使用Promise
JavaScript中的异步编程一直是开发中的重要话题。传统的回调函数带来了回调地狱和代码可读性的问题。为了解决这些问题,ES6引入了Promise,一种更现代、更灵活的异步编程解决方案。本文将深入探讨JavaScript中如何使用Promise,通过丰富的示例代码演示Promise的基本概念、链式调用、错误处理等方面的用法,帮助大家更全面地理解和应用Promise。
|
5月前
|
前端开发 JavaScript 测试技术
ES6:什么是Promise
ES6:什么是Promise
|
5月前
|
前端开发 JavaScript
ES6中什么是Promise?
ES6中什么是Promise?
|
15天前
|
前端开发 JavaScript
ES6:Promise使用方法解析大全
ES6:Promise使用方法解析大全
|
4月前
|
前端开发 JavaScript
No101.精选前端面试题,享受每天的挑战和学习(Promise)
No101.精选前端面试题,享受每天的挑战和学习(Promise)
|
4月前
|
前端开发 JavaScript
JavaScript学习 -- Promise的使用
JavaScript学习 -- Promise的使用
17 0
|
4月前
|
资源调度 前端开发 JavaScript
vue - ES6模块化、promise、webpack打包(所在在学的朋友们先看这篇,看了不吃亏)...
vue - ES6模块化、promise、webpack打包(所在在学的朋友们先看这篇,看了不吃亏)...
|
4月前
|
设计模式 前端开发
Promise 与 Axios 的一些学习心得记录
Promise 与 Axios 的一些学习心得记录
29 0