VIP用户交流群:462197261 收藏本站北冥有鱼 互联网前沿资源第一站 助力全行业互联网+
在线客服:78895949
tonglan
  • 当前位置:
  • 深入理解JS异步编程-Promise

    前言

    “JS 是基于单线程事件循环”的概念构建的,回调函数不会立即执行,由事件轮询去检测事件是否执行完毕,当执行完有结果后,将结果放入回调函数的参数中,然后将回调函数添加到事件队列中等待被执行。

    同时也讲了回调函数的问题:

    一是“回调地狱”,因为异步回调函数的特点:回调函数是作为异步函数的参数,一层一层嵌套,当嵌套过多,将使代码逻辑变得混乱,也无法做好错误捕捉和处理(只能在回调函数内部 try catch)。

    二是回调的执行方式不符合自然语言的线性思维方式,不容易被理解。

    三是控制反转(控制权在其他人的代码上),假如异步函数是别人提供的库,我们把回调函数传进去,我们并不能知道异步函数在调用回调函数之外做了什么事情。

    func1(() => {
    func2(() => {
    func3(() => {
    func4(() => {
    try {
    ...
    } catch (err){
    ...
    }
    })
    });
    });
    });
    

    一、Promise 原理

    首先,Promise 中文翻译为“承诺”, 是 JavaScript 的一种对象,表示承诺终将返回一个结果,无论成功还是失败。
    Promise 有三个状态:等待中(pending),完成(fullfilled),失败(rejected), Promise 的设计具有原子性,状态一旦从 pending 状态转换为 fullfilled 状态或者 rejected 状态后,将不能被改变。

    var promise1 = new Promise((resolve, reject) => {
    console.log("Promise 构造器会立即执行");
    setTimeout(function (){
    if(true) {
    resolve("完成");
    } else {
    reject("失败");
    }
    }, 1000);
    })
    promise1
    .then((result) => {
    // do something
    console.log(result);
    return 1
    // return Promise.resolve(1); // 返回一个决议为成功的 promise 实例
    // return Promise.reject("error"); // 返回一个决议为拒绝的 Promise 实例
    })
    .then((result) => {
    // .then() 方法会返回一个 promise, 完成调用的参数为前一个 promise 的返回值或者决议值。
    // do other things
    console.log(result);
    throw new Error("错误") // 抛出错误是隐式拒绝
    })
    .catch((error) => {
    // 捕捉错误
    console.log(error)
    })
    .then(() => {
    // 还能继续执行!
    })
    .finally(() => {
    // always do somethings
    console.log("finally!")
    })

    二、Promise 的优势

    1.链式调用

    Promise 使用 then 方法后还会返回一个新的 Promise 对象,便于我们传递状态数据,同时链式写法接近于同步写法,更符合线性思维。

    2.错误捕捉

    相比回调函数的错误无法在外部捕捉的问题,Promise 能够为一连串的异步调用提供错误处理。

    3.控制反转再反转

    由于第三方提供的异步函数,无法保证回调函数如何被执行,但是 Promise 的特点,能够保证异步函数只能被 resolve 一次,以及始终以异步的形式执行代码。

    4.可以利用 Promise.all 和 Promise.race 来解决 Promise 始终未决议和并行 Promise 嵌套的问题

    三、Promise 的不足

    1.每个 .then() 都是一个独立的作用域

    加入有很多个 .then() 方法,就会创建很多个独立的作用域,那么将只能通过外面包裹一层函数作用域的闭包来共享状态数据

    2.无法取消单个 .then()

    当 Promise 链中任意一个 .then() 方法中有语句执行错误后,尽管经过 catch 方法的错误处理,还是并不会中断整个 Promise 链的执行。

    3.无法得知进度

    由于 Promise 只能从 pending 到 fullfilled 或 rejected 状态,无法得知 pending 阶段的进度。

    四、Promise 应用

    // Promise 封装 ajax
    function fetch(method, url, data){
    return new Promise((resolve, reject) => {
    var xhr = new XMLHttpRequest();
    var method = method || "GET";
    var data = data || null;
    xhr.open(method, url, true);
    xhr.onreadystatechange = function() {
    if(xhr.status === 200 && xhr.readyState === 4){
    resolve(xhr.responseText);
    } else {
    reject(xhr.responseText);
    }
    }
    xhr.send(data);
    })
    }
    // 使用
    fetch("GET", "/some/url.json", null)
    .then(result => {
    console.log(result);
    })
    // 封装 nodejs error first 风格回调
    function readFile(url) {
    return new Promise((resolve, reject) => {
    fs.readFile(url,'utf8', (err, data) => {
    if(err) {
    reject(err);
    return;
    }
    resolve(data)
    }) 
    })
    }
    

    五、总结

    Promise 是 ES6 提出的简化异步流程控制新规范,强调异步任务的完成状态且具有原子性,这使得我们的代码更容易追踪和维护。Promise 在事件轮询中属于异步事件队列中的微任务,而微任务总是一次性全部执行,而宏任务是每轮轮询执行一个。

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持北冥有鱼。

    您可能感兴趣的文章:

    • javascript异步编程的六种方式总结
    • nodejs异步编程基础之回调函数用法分析
    • Javascript实现异步编程的过程
    • 详解JavaScript异步编程中jQuery的promise对象的作用
    • 跟我学习javascript解决异步编程异常方案
    • 异步JavaScript编程中的Promise使用方法
    • 深入理解JavaScript编程中的同步与异步机制
    • 新手如何快速理解js异步编程

    广而告之:
    热门推荐:
    详解create-react-app 自定义 eslint 配置

    使用eslint和editorconfig规范代码 为什么要用这些: 代码规范有利于团队协作 纯手工规范耗时耗力而且不能保证准确性 能配合编辑器自动提醒错误,提高开发效率 eslint 随着ECMAScript版本一直更新的Js lint工具,插件丰富,并且能够套用规范,规则非常丰富,能够满足大部分团···

    MySQL存储引擎基础知识

    在之前的文章中我们说过MySQL事务,现在大家都应该知道了MySQL事务了吧,还记得事务的ACID原则吗?不记得的童鞋可以回顾一下《MySQL之事务初识》,其实呀,更严谨一点的话,应该是MySQL InnoDB存储引擎,因为在MySQL中,只有InnoDB存储引擎才支持事务。看到此处,有些朋友可能···

    html table表数据转Json格式示例代码

    <table>表数据转 Json 格式的javascript函数如下 复制代码 代码如下: <script> var keysArr = new Array("key0", "key1","key2"); function TableToJson(tableid) { //tableid是你要转化的表的表名,是一个字符串,如"example" var rows = document.getElementBy···

    DedeCMS 修改专题文章命名规则的方法

    专题文章在发布后,默认是 arc-加文章id.html 形式命名的  如何修改这个默认命名规则呢    专题不像栏目可以自定义    本来是求助帖子的,经过不懈努力终于找到了  /include/channelunit.func.php  查找 arc- 将其替换成其他参数 ···

    PHP屏蔽关键字实现方法

    本文介绍了PHP屏蔽关键字实现方法,一共有两种实现方式,具体如下: 第一种方法 思路 用正则去匹配关键字,把关键字用别的字符替换 $str = "/你大爷|你麻痹|什么玩意|SB|你他妈/"; // 关键字正则字符串 $string = "你他妈干什么玩意了 SB"; // 文本字符串 echo p···

    原生js实现拖拽功能基本思路详解

    如果要设置物体拖拽,那么必须使用三个事件,并且这三个事件的使用顺序不能颠倒。 1.onmousedown:鼠标按下事件 2.onmousemove:鼠标移动事件 3.onmouseup:鼠标抬起事件   拖拽的基本原理就是根据鼠标的移动来移动被拖拽的元素。鼠标的移动也就是x、y坐标的变化;元素的移···

    html发送邮件通过Mailto简单实现

    最近给客户的页脚的邮箱加上点击发送邮件功能,自己百度了下,解决方法很简单 1简单的做个链接就行了 复制代码 代码如下: <a href="Mailto:test@163.com">给我发邮件</a> 2. 复杂的链接 代码: 复制代码 代码如下: <pre name="code" class="html"><···

    PHP设计模式之建造者模式定义与用法简单示例

    本文实例讲述了PHP设计模式之建造者模式。分享给大家供大家参考,具体如下: 建造者模式: 将复杂对象的创建过程和表示进行分离(好吧,我也看不懂什么意思1)。 来点我人类能听懂的话: 1、在客户端看来需要的仅仅是实例化后的类对象(大多数情况下是需要类的属性)。 2、传···

    MySQL如何清空慢查询文件

    一、概述 本章主要写当慢查询文件很大的时候怎样在线生成一个新的慢查询文件。 测试环境:mysql 5.6.21 二、步骤 配置慢查询 默认的my.cnf文件在/etc/目录下 vim /etc/my.cnf #slow_query slow_query_log=1#开启慢查询 slow_query_log_file=/var/lib/mysql/mysql-slow.log #···

    php 5.4 全新的代码复用Trait详解

    从PHP的5.4.0版本开始,PHP提供了一种全新的代码复用的概念,那就是Trait。Trait其字面意思是"特性"、"特点",我们可以理解为,使用Trait关键字,可以为PHP中的类添加新的特性。 熟悉面向对象的都知道,软件开发中常用的代码复用有继承和多态两种方式。在PHP中,只能实现单继承。而Tra···