zoukankan      html  css  js  c++  java
  • 读书笔记:深入理解ES6(十一)

    第十一章 Promise与异步编程

      Promise可以实现其他语言中类似Future和Deferred一样的功能,是另一种异步编程的选择,它既可以像事件和回调函数一样指定稍后执行的代码,也可以明确指示代码是否成功执行。

    第1节 异步编程的背景知识

      1. 机制

        JavaScript引擎是基于单线程(Single-threaded)事件循环的概念构建,即同一时刻只允许一个代码块在执行。这些代码块被放在一个任务队列(job queue)中,每当一段代码准备执行时,都会被添加到任务队列。每当JavaScript引擎中的一段代码结束执行,事件循环(event loop)会执行队列中下一个任务。事件循环是JavaScript引擎的一段代码,负责监控代码执行并管理任务队列。

      2. 事件模型

        例如点击按钮或者按下键盘按键会触发的onclick事件,是JavaScript中最基础的异步编程形式。尽管事件模型适用于响应用户交互和完成类似的低频功能,但对更复杂的需求来说却不是很灵活。

      3. 回调模式

        回调模式和事件模型类似,异步代码都会在未来的某个时间点执行,二者的区别是回调模式中被调用的函数是作为参数传入的。例如:

    1 readFile("example.txt", function(err, contents) {
    2     if (err) {
    3         throw err;
    4     }
    5     console.log(contents);
    6 });
    7 console.log("Hi");

        相比之下,回调模式比事件模型更灵活,但想要实现更复杂的功能时,回调函数的局限性同样会显现出来。

    第2节 Promise的基础知识

      Promise相当于异步操作结果的占位符,它不去订阅事件,也不会传递一个回调函数给目标参数,而是让函数返回一个Promise。例如:

    1 //readFile承诺将在未来某一个时刻完成
    2 let promise = readFile("example.txt");

      1. Promise的声明周期

        a) Promise先是处于进行中(pending)的状态,此时操作尚未完成;等异步操作执行结束后,Promise变为已处理(settled)状态。分为如下两种状态:

        

        b)Promise的状态改变时,调用then()方法来采取特定的行动。

          then()方法接受2个参数:第一个参数是变为fulfilled时要调用的函数,第2个是状态变为rejected时需要调用的函数。

          Promise还有一个catch()方法,相当于只给其传入拒绝处理程序的then()方法。

      2. 创建未完成的Promise

        用Promise构造函数可以创建新的Promise,构造函数只接受一个参数:包含初始化Promise代码的执行器(executor)函数。执行器接受2个参数,分别是执行成功完成时调用的resolve()函数,执行失败时,调用reject()函数。

        执行器函数会立即执行,然后才执行后续流程中的代码(即resolve() / reject()会放到任务队列中再执行)。

      3. 创建已处理的Promise

        使用Promise.resolve() / Promise.reject()来实现根据特定的值来创建已解决的Promise。例如:

    1 let promise = Promise.resolve(42);
    2 promise.then(function(value) {
    3     console.log(value); //42
    4 });
    5 
    6 let promise = Promise.reject(42);
    7 promise.catch(function(value){
    8     console.log(value); // 42
    9 });

      4. 执行器错误

        每个执行器中都隐含一个try-catch块,所以错误会被捕获并传入拒绝处理程序。

    第3节 全局的Promise拒绝处理

      如果在没有拒绝处理程序的情况下,拒绝一个Promise,那么不会提示信息。Promise的特性决定了很难检测一个Promise是否被处理过。Node.js和浏览器分别做了一些改变来解决开发者这个痛点。

      1. Node.js环境的拒绝处理

        在Node.js中,处理Promise拒绝时会触发Promise对象上的两个事件:

        ·unhandledRejection  在一个事件循环中,当Promise被拒绝,并且没有提供拒绝处理程序时,触发该事件。

        ·rejectionHandled  在一个事件循环后,当Promise被拒绝,若拒绝处理程序被调用,触发该事件。

        具体代码参考P.249

      2. 浏览器环境的拒绝处理

        a) 浏览器也是通过触发两个事件来识别未处理的拒绝的,虽然这些事件是在window对象上触发的,但实际上与Node.js中完全等效。

          ·unhandledRejection  在一个事件循环中,当Promise被拒绝,并且没有提供拒绝处理程序时,触发该事件。

          ·rejectionHandled  在一个事件循环后,当Promise被拒绝,若拒绝处理程序被调用,触发该事件。

        b) 在Node.js实现中,事件处理程序接受多个参数;而在浏览器中,事件处理程序接受一个有以下属性的事件对象作为参数:

          ·type  事件名称("unhandledReject"或“rejectionHandled”);

          ·promise  被拒绝的Promise对象

          ·reason  来自Promise的拒绝值

        c) 浏览器实现的另一处不同是,在两个事件中都可以使用拒绝值(reason)。代码参考:P.251

    第4节 串联Promise

      记住一个原则:只有当第一个Promise完成或被拒绝后,第二个才会被解决。

      1. 捕获错误

        在完成处理程序和拒绝处理程序中可能也会发生错误,而Promise链可以用来捕获这些错误。

        链式Promise调用可以感知到链中其他Promise的错误。

      2. Promise链的返回值

         Promise链的另一个重要特性是可以给下游Promise传递数据。在完成处理程序和拒绝处理程序中都可以这么做。

           代码参考P.255

      3. 在Promise链中返回Promise

        先定义的Promise的执行器先执行,后定义的后执行。

    第5节 响应多个Promise

      之前讲的都是单Promise响应。如果想通过监听多个Promise来决定下一步的操作,可以使用ES6提供的Promise.all()和Promise.race()两个方法来监听多个Promise。

      1. Promise.all()方法

        该方法只接受一个参数并返回一个Promise,该参数是一个含有多个受监视Promise的可迭代对象,只有当可迭代对象中所有Promise都被解决后,返回的Promise才会被解决,只有当可迭代对象中所有Promise都被完成后返回的Promise才会被完成。

        其中,有两种情况:

        

         我们看看这两种情况,分别怎么处理:

           1. 当迭代对象中所有的Promise都被解决并返回后,最后的Promise里面存的值按照传入参数数组中的Promise的顺序储存。例如:

     1 let p1 = new Promise(function(reolve, reject) {
     2     resolve(42);
     3 });
     4 
     5 let p2 = new Promise(function(resolve, reject) {
     6     resolve(43);
     7 });
     8 
     9 let p3 = new Promise(function(resolve, reject) {
    10     resolve(44);
    11 });
    12 
    13 let p4 = Promise.all([p1, p2, p3]);
    14 
    15 p4.then(function(value) {
    16     console.log( Array.isArray(value) ); // true
    17     console.log( value[0] ); // 42
    18     console.log( value[1] ); // 43
    19     console.log( value[2] ); // 44
    20 });

          2.当迭代对象中有被拒绝的Promise时,只要有一个被拒绝,那么返回的Promise没等所有Promise都完成就立即被拒绝,例如:

     1 let p1 = new Promise(function(reolve, reject) {
     2     resolve(42);
     3 });
     4 
     5 let p2 = new Promise(function(resolve, reject) {
     6     reject(43);
     7 });
     8 
     9 let p3 = new Promise(function(resolve, reject) {
    10     resolve(44);
    11 });
    12 
    13 let p4 = Promise.all([p1, p2, p3]);
    14 
    15 p4.then(function(value) {
    16     console.log( Array.isArray(value) ); // true
    17     console.log( value ); // 43
    18 });

      2. Promise.race()方法

        Promise.race()与Promise.all()稍有不同。在可迭代对象中,只要有一个Promise被解决,返回的Promise就解决,无须等到所有Promise都被完成。

        如果先解决的是已完成Promise,则返回已完成Promise;如果先解决的是已拒绝的Promise,则返回已拒绝Promise。看个例子:

     1 let p1 = new Promise(function(resolve, reject) {
     2     setTimeout(function() {resolve(42);}, 0);
     3 });
     4 
     5 let p2 = Promise.reject(43);
     6 
     7 let p3 = new Promise(function(resolve,reject) {
     8     resolve(44)
     9 });
    10 
    11 let p4 = Promise.race([p1, p2, p3]);
    12 
    13 p4.catch(function(value) {
    14     console.log(value); // 43
    15 });

    第6节 自Promise继承

      Promise也是基类,因为也可以派生其它类。

      例子参考代码P.262

    第7节 基于Promise的异步任务执行

      只要每个异步操作都返回Promise,以Promise作为通用接口用于所有异步代码可以简化任务执行器。

      例子参考代码P.265

    (本节完)

  • 相关阅读:
    下载文件总结
    用PHP,怎么获取PHP.ini中的文件上传最大的字节数。也就是默认的2M
    TP框架下载功能 - 不想下天桥 - 博客园
    CSS,font-family,好看常用的中文字体
    安装Wamp后 Apache无法启动的解决方法
    :nth-child(n)
    list-style
    netbeans常用快捷键
    ideaic快捷键
    配置nutch
  • 原文地址:https://www.cnblogs.com/zxxsteven/p/11518826.html
Copyright © 2011-2022 走看看