Promise 对象

是 JavaScript 的异步操作解决方案,为异步操作提供统一接口。

目前 JavaScript 原生支持 Promise 对象

它起到代理作用(proxy),充当异步操作回调函数之间的中介,使得异步操作具备同步操作的接口。

Promise 可以让异步操作写起来,就像在写同步操作的流程,而不必一层层地嵌套回调函数。

  • Promise 是一个对象,也是一个构造函数

    function f1(resolve, reject) {
    // 异步代码...
    } var p1 = new Promise(f1);
    // Promise 构造函数接受一个回调函数 f1() 作为参数,f1() 里面是异步操作的代码。然后,返回的p1 就是一个 Promise 实例
  • Promise 的设计思想

    • 所有异步任务都返回一个 Promise 实例。
      • Promise 实例有一个 then 方法,用来指定下一步的回调函数。

        var p1 = new Promise(f1);
        p1.then(f2);

        f1() 的异步操作执行完成,就会执行 f2()

    • 不仅改善了可读性,而且对于多层嵌套的回调函数尤其方便。

      • 传统的写法可能需要把 f2() 作为回调函数传入 f1(),比如写成f1(f2),异步操作完成后,在 f1() 内部调用 f2()。
      • 而 Promise 使得 f1() 和 f2() 变成了链式写法。
        // 传统写法
        step1(function (value1) {
        step2(value1, function(value2) {
        step3(value2, function(value3) {
        step4(value3, function(value4) {
        // ...
        });
        });
        });
        }); // Promise 的写法
        (new Promise(step1)).then(step2).then(step3).then(step4);
  • 通过自身的状态,来控制异步操作。
  • Promise 实例具有三种状态
      • 异步操作未完成(pending)
      • 异步操作成功(fulfilled)
      • 异步操作失败(rejected)
    • 上面三种状态里面,fulfilled 和 rejected合在一起称为 resolved(已定型)。
    • 这三种的状态的变化途径只有两种:
      • 从 “未完成” 到 “成功”
      • 从 “未完成” 到 “失败”
    • 它的英语意思是“承诺”,一旦承诺成效,就不得再改变了。
    • 一旦状态发生变化,就凝固了,不会再有新的状态变化。
    • 这也意味着,Promise 实例的状态变化只可能发生一次。
  • Promise 构造函数

    • JavaScript 提供原生的 Promise 构造函数,用来生成 Promise 实例

      • var promise = new Promise(function (resolve, reject) {
        // ... if (/* 异步操作成功 */){
        resolve(value);
        } else { /* 异步操作失败 */
        reject(new Error());
        }
        });
        // 该函数的两个参数分别是 resolve reject 。它们是两个函数,由 JavaScript 引擎提供,不用自己实现
      • resolve() 函数

        • 作用是,将Promise实例的状态从“未完成”变为“成功”(即从pending变为fulfilled)

        • 在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。

      • reject函数

        • 作用是,将Promise实例的状态从“未完成”变为“失败”(即从pending变为rejected)

        • 在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

    • 实例
      • function timeout(ms) {
        return new Promise((resolve, reject) => {
        setTimeout(resolve, ms, 'done');
        });
        } timeout(100)

        上面代码中,timeout(100) 返回一个 Promise 实例。100毫秒以后,该实例的状态会变为 fulfilled

  • Promise.prototype.then() 

    • Promise 实例的then方法,用来添加回调函数
    • 可以接受两个回调函数,一旦状态改变,就调用相应的回调函数。
      • 第一个是异步操作成功时(变为fulfilled状态)的回调函数
      • 第二个是异步操作失败(变为rejected)时的回调函数(该参数可以省略)。
        • var p1 = new Promise(function (resolve, reject) {
          resolve('成功');
          });
          p1.then(console.log, console.error); // "成功" var p2 = new Promise(function (resolve, reject) {
          reject(new Error('失败'));
          });
          p2.then(console.log, console.error); // Error: 失败
        • p1 和 p2 都是Promise 实例,它们的 then() 方法绑定两个回调函数:成功时的回调函数 console.log,失败时的回调函数 console.error(可以省略)。

        • p1 的状态变为成功,p2 的状态变为失败

        • 对应的回调函数会收到异步操作传回的值,然后在控制台输出

  • 实例:图片加载

    • 使用 Promise 完成图片的加载

      • var preloadImage = function (path) {
        return new Promise(function (resolve, reject) {
        var image = new Image();
        image.onload = resolve;
        image.onerror = reject;
        image.src = path;
        });
        };
      • 调用

        preloadImage('https://example.com/my.jpg')
        .then(function (e) { document.body.append(e.target) })
        .then(function () { console.log('加载成功') })
  • 强大之处:

    • 让回调函数变成了规范的链式写法,程序流程可以看得很清楚。
    • 它有一整套接口,可以实现许多强大的功能,
      • 比如同时执行多个异步操作,等到它们的状态都改变以后,再执行一个回调函数
      • 再比如,为多个回调函数中抛出的错误,统一指定处理方法等等。
    • 它的状态一旦改变,无论何时查询,都能得到这个状态。
      • 这意味着,无论何时为 Promise 实例添加回调函数,该函数都能正确执行。
      • 所以,你不用担心是否错过了某个事件或信号。
      • 如果是传统写法,通过监听事件来执行回调函数,一旦错过了事件,再添加回调函数是不会执行的。
  • 微任务(Microtask)

    • Promise 的回调函数属于异步任务,会在同步任务之后执行。

      • new Promise(function (resolve, reject) {
        resolve(1);
        }).then(console.log); console.log(2);
        //
        // 1
        // 上面代码会先输出 2,再输出 1 。
        // 因为 console.log(2)是同步任务,而 then 的回调函数属于异步任务,一定晚于同步任务执行
    • Promise 的回调函数不是正常的异步任务,而是微任务(microtask)
    • 它们的区别在于
      • 正常任务追加到下一轮事件循环
      • 微任务追加到本轮事件循环
      • 这意味着,微任务的执行时间一定早于正常任务。
    • setTimeout(function() {
      console.log(1);
      }, 0); new Promise(function (resolve, reject) {
      resolve(2);
      }).then(console.log); console.log(3);
      //
      //
      //
    • 输出结果是321。这说明 then 的回调函数的执行时间,早于setTimeout(fn, 0)。

    • 因为 then 是本轮事件循环执行,setTimeout(fn, 0)在下一轮事件循环开始时执行

(84)Wangdao.com第十八天_JavaScript Promise 对象的更多相关文章

  1. (84)Wangdao.com第十八天_JavaScript 文档对象模型 DOM

    文档对象模型 DOM DOM 是 JavaScript 操作网页的接口, 全称为“文档对象模型”(Document Object Model). 作用是将网页转为一个 JavaScript 对象,从而 ...

  2. (73)Wangdao.com第十二天_JavaScript consol 对象与控制台

    consol 对象 console对象是 JavaScript 的原生对象 它有点像 Unix 系统的标准输出stdout和标准错误stderr, 可以输出各种信息到控制台,并且还提供了很多有用的辅助 ...

  3. (85)Wangdao.com第十八天_JavaScript NodeList 接口,HTMLCollection 接口

    NodeList 接口        HTMLCollection 接口 节点都是单个对象,有时需要一种数据结构,能够容纳多个节点 DOM 提供两种节点集合,用于容纳多个节点:NodeList 和 H ...

  4. angular学习笔记(二十八-附2)-$http,$resource中的promise对象

    下面这种promise的用法,我从第一篇$http笔记到$resource笔记中,一直都有用到: HttpREST.factory('cardResource',function($resource) ...

  5. ES6深入学习记录(二)promise对象相关

    1.Promise的含义 Promise是异步编程的一种解决方案,比传统的解决方案--回调函数和事件更合理和强大.ES6将其写进了语言标准,统一了用法,原生提供了promise对象. 所谓Promis ...

  6. es6中的promise对象

    Promise是异步里面的一种解决方案,解决了回调嵌套的问题,es6将其进行了语言标准,同意了用法,提供了`promise`对象, promise对象有三种状态:pending(进行中) .Resol ...

  7. ES6的promise对象应该这样用

    ES6修补了一位Js修真者诸多的遗憾. 曾几何时,我这个小白从js非阻塞特性的坑中爬出来,当我经历了一些回调丑陋的写法和优化的尝试之后,我深深觉得js对于多线程阻塞式的开发语言而言,可能有着其太明显的 ...

  8. Angularjs promise对象解析

    1.先来看一段Demo,看完这个demo你可以思考下如果使用$.ajax如何处理同样的逻辑,使用ng的promise有何优势? var ngApp=angular.module('ngApp',[]) ...

  9. JavaScript异步编程(1)- ECMAScript 6的Promise对象

    JavaScript的Callback机制深入人心.而ECMAScript的世界同样充斥的各种异步操作(异步IO.setTimeout等).异步和Callback的搭载很容易就衍生"回调金字 ...

随机推荐

  1. [再寄小读者之数学篇](2014-04-18 from 352558840@qq.com [南开大学 2014 年高等代数考研试题]反对称矩阵的组合)

    (2014-04-18 from 352558840@qq.com [南开大学 2014 年高等代数考研试题]反对称矩阵的组合) 设 ${\bf A},{\bf B}$ 都是反对称矩阵, 且 ${\b ...

  2. 数据库的URL格式

    Oracle数据库: 驱动jar包: ojdbc6.jar 驱动程序类名字:oracle.jdbc.OracleDriver JDBC URL:jdbc:oracle:thin:@//<host ...

  3. css实现移动端水平滚动导航

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  4. 版本控制工具 - Git

    版本控制工具 - Git 安装完成后,打开Git Bash,这是一个命令行工具,用于操作仓库和仓库的文件.你可以通过命令将已经存在的项目变成仓库,也可以重新创建一个新项目再通过命令将其变成仓库,还可以 ...

  5. 浅谈axios

    在我们的项目中有用到: fetch有直接用的,也有自己封装之后用的; vue-resource在vue1的时候使用,把方法抽象出来后,总需要往方法里传 this.$http ,感觉是个超级不爽的设计, ...

  6. bat执行python脚本,执行多条命令

    1.新建一个txt文档,输入以下命令 @echo offcmd /k python F:\Pycharm_Projection\Test\test2.py 2.将txt文档保存为.bat格式,然后双击 ...

  7. mysql之concat concat_ws group_concat

    concat.concat_ws.group_concat都可以用来连接字符串. concat和concat_ws用来连接同一行中不同列的数据,group_ws用来连接同一列的数据. 格式如下: co ...

  8. excel生成数据地图

    在数据分析过程中,图表是一个十分重要的部分,通过图表可以清晰明了的说明一些数字特征.在众多数据分析图表中,数据地图是常用的一中分析图.在一般的数据分析中,excel已经可以满足绝大部分功能.在本文中, ...

  9. js设置document.domain实现跨域

    document.domain 只能实现跨子域的问题 如:xxx.com/a.html 和aaa.xxx.com/b.html 或:bbb,xxx.com/c.html 和ccc.xxx.com/d. ...

  10. windows配置Erlang环境

    1.说明 1.1 操作系统 win10x64 1.2 Erlang(['ə:læŋ])是一种通用的面向并发的编程语言,它由瑞典电信设备制造商爱立信所辖的CS-Lab开发,目的是创造一种可以应对大规模并 ...