美文网首页
ES6之Promise

ES6之Promise

作者: 27亿光年中的小小尘埃 | 来源:发表于2019-12-20 01:06 被阅读0次

    Promise 基础

    Promise 是为异步操作的结果所准备的占位符。是解决异步编程的一种方法,是规避回调地狱(callbacK hell)的一种解决方案

    Promise 的生命周期

    • 创建时是一个未决状态,白话文就是还没有决定结果
    • 已完成( fulfilled ): Promise 的异步操作已成功结束;
    • 已拒绝( rejected ): Promise 的异步操作未成功结束,可能是一个错误,或由其他原
      因导致。

    Promise的方法

    promise有以下方法:

    • then()
    • catch()
    • all()
    • race()

    then()方法

    promise.then()接受两个参数。第一个参数是Promise被完成时要调用的函数,与异步操作关联的任何附加数据都会被传入这个完成函数。第二个参数则是Promise被拒绝时要调用的函数,与完成函数相似,拒绝函数会被传入与拒绝相关联的任何附加数据。

    如下:

    let promise = readFile("example.txt");
    promise.then(function(contents) {
        // 完成
        console.log(contents);
    }, function(err) {
        // 拒绝
        console.error(err.message);
    });
    
    

    catch()方法

    其行为等同于只传递拒绝处理函数给 then() 。例如,以下的 catch() 与then()调用是功能等效的。

    promise.catch(function(err) {
        // 拒绝
        console.error(err.message);
    });
    // 等同于:
    promise.then(null, function(err) {
        // 拒绝
        console.error(err.message);
    });
    
    

    创建一个未决的Promise()

    新的 Promise 使用 Promise 构造器来创建。此构造器接受单个参数:一个被称为执行器(
    executor )的函数,包含初始化 Promise 的代码。该执行器会被传递两个名为 resolve()
    与 reject() 的函数作为参数。 resolve() 函数在执行器成功结束时被调用,用于示意该
    Promise 已经准备好被决议( resolved ),而 reject() 函数则表明执行器的操作已失败。

    // Node.js 范例
    let fs = require("fs");
    function readFile(filename) {
        return new Promise(function(resolve, reject) {
            // 触发异步操作
            fs.readFile(filename, { encoding: "utf8" }, function(err, contents) {
                // 检查错误
                if (err) {
                    reject(err);
                    return;
                }
                // 读取成功
                resolve(contents);
            });
        });
    }
    let promise = readFile("example.txt");
    // 同时监听完成与拒绝
    promise.then(function(contents) {
        // 完成
        console.log(contents);
    }, function(err) {
        // 拒绝
        console.error(err.message);
    });
    
    //等同于
    promise.then((contents)=>{
        // 完成
        console.log(contents);
    }).catch((err)=>{
        // 拒绝
        console.error(err.message);
    });
    

    以上是一个基本的Promise模型,then()方法执行fs.readFile()读取文件成功后的回调函数,catch()方法执行读取文件失败后的错误回调

    创建已决的 Promise

    即创建的时候就决定了结果,Promise.resolve() 方法接受单个参数并会返回一个处于完成态的 Promise 。

    let promise = Promise.resolve(42);
    promise.then(function(value) {
        console.log(value); // 42
    });
    

    Promise.reject() 方法来创建一个已拒绝的 Promise 。此方法像Promise.resolve() 一样工作,区别是被创建的 Promise 处于拒绝态

    let promise = Promise.reject(42);
    promise.catch(function(value) {
        console.log(value); // 42
    });
    

    非 Promise 的 Thenable

    Promise.resolve() 与 Promise.reject() 都能接受非 Promise 的 thenable 作为参数。当传
    入了非 Promise 的 thenable 时,这些方法会创建一个新的 Promise ,此 Promise 会在
    then() 函数之后被调用。

    当一个对象拥有一个能接受 resolve 与 reject 参数的 then() 方法,该对象就会被认为是
    一个非 Promise 的 thenable ,就像这样:

    let thenable = {
        then: function(resolve, reject) {
            resolve(42);
        }
    };
    

    此例中的 thenable 对象,除了 then() 方法之外没有任何与 Promise 相关的特征。你可以
    调用 Promise.resolve() 来将 thenable 转换为一个已完成的 Promise :

    let thenable = {
        then: function(resolve, reject) {
            resolve(42);
        }
    };
    let p1 = Promise.resolve(thenable);
    p1.then(function(value) {
    console.log(value); // 42
    });
    
    

    链式Promise

    每次对 then() 或 catch() 的调用实际上创建并返回了另一个 Promise ,仅当前一个
    Promise 被完成或拒绝时,后一个 Promise 才会被决议。

    因此我们可以进行链式调用

    let p1 = new Promise(function(resolve, reject) {
        resolve(42);
    });
    p1.then(function(value) {
        console.log(value);
        return value+1
    }).then(function(val) {
        console.log(val);
    }).catch((err)=>{
        
    });
    
    

    以上中第一个then方法会作为第二个then方法的入参,把then方法的返回值一直传递下去,Promise 链允许你捕获前一个 Promise 的完成或拒绝处理函数中发生的错误。因此只要有某个then方法出现错误,或者直接失败就会调用catch方法

    在 Promise 链中返回 Promise

    从完成或拒绝处理函数中返回一个基本类型值,能够在Promise之间传递数据,但若你返回的是一个对象呢?若该对象是一个 Promise ,那么需要采取一个额外步骤来决定如何处理。

    let p1 = new Promise(function(resolve, reject) {
        resolve(42);
    });
    let p2 = new Promise(function(resolve, reject) {
        resolve(43);
    });
    p1.then(function(value) {
        // 第一个完成处理函数
        console.log(value); // 42
        return p2;
    }).then(function(value) {
        // 第二个完成处理函数
        console.log(value); // 43
    })catch((err)=>{
        
    });
    
    

    在此代码中, p1 安排了一个决议 42 的作业, p1 的完成处理函数返回了一个已处于决议态的 Promise : p2 。由于 p2 已被完成,第二个完成处理函数就被调用了。而若p2被拒绝,会调用拒绝处理函数(如果存在的话),而不调用第二个完成处理函数。

    Promise.all() 方法

    Promise.all() 方法接收单个可迭代对象(如数组)作为参数,并返回一个 Promise 。这个可迭代对象的元素都是 Promise ,只有在它们都完成后,所返回的 Promise 才会被完成。

    let p1 = new Promise(function(resolve, reject) {
        resolve(42);
    });
    let p2 = new Promise(function(resolve, reject) {
        resolve(43);
    });
    let p3 = new Promise(function(resolve, reject) {
        resolve(44);
    });
    let p4 = Promise.all([p1, p2, p3]);
    p4.then(function(value) {
        console.log(Array.isArray(value)); // true
        console.log(value[0]); // 42
        console.log(value[1]); // 43
        console.log(value[2]); // 44
    });
    
    

    此处前面的每个 Promise 都用一个数值进行了决议,对 Promise.all() 的调用创建了新的Promise p4 ,在 p1 、 p2 与 p3 都被完成后, p4 最终会也被完成。传递给 p4 的完成处理函数的结果是一个包含每个决议值( 42 、 43 与 44 )的数组,这些值的存储顺序保持了待决议的 Promise 的顺序(与完成的先后顺序无关),因此你可以将结果匹配到每个
    Promise 。

    若传递给 Promise.all() 的任意 Promise 被拒绝了,那么方法所返回的 Promise 就会立刻被拒绝,而不必等待其他的 Promise 结束

    也就是说只要数组里面的promise有一个执行失败,Promise.all()就会立马执行失败决议,调用catch()方法

    Promise.race() 方法

    Promise.race()跟Promise.all()方法入参都一样,只是Promise.race()是只要有一个Promise执行成功决议,Promise.race()就执行成功决议

    这两种方法十分类似于数组的every()方法和some()方法

    继承 Promise

    正像其他内置类型,你可将一个Promise用作派生类的基类。这允许你自定义变异的Promise,在内置Promise的基础上扩展功能。例如,假设你想创建一个可以使用success()与failure()方法的Promise,对常规的then()与catch()方法进行扩展,可以像下面这样创建该 Promise 类型:

    class MyPromise extends Promise {
        // 使用默认构造器
        success(resolve, reject) {
            return this.then(resolve, reject);
        }
        failure(reject) {
            return this.catch(reject);
        }
    }
    let promise = new MyPromise(function(resolve, reject) {
        resolve(42);
    });
    promise.success(function(value) {
    console.log(value); // 42
    }).failure(function(value) {
    console.log(value);
    });
    
    

    可以封装自己的Promise哦!

    总结

    Promise 被设计用于改善 JS 中的异步编程,与事件及回调函数对比,在异步操作方面为你提供了更多的控制权与组合性。 Promise 调度被添加到 JS 引擎作业队列,以便稍后执行。不过此处有另一个作业队列追踪着Promise的完成与拒绝处理函数,以确保适当的执行。

    Promise 具有三种状态:挂起、已完成、已拒绝。一个Promise起始于挂起态,并在成功时转为完成态,或在失败时转为拒绝态。在这两种情况下,处理函数都能被添加以表明Promise何时被解决。then()方法允许你绑定完成处理函数与拒绝处理函数,而 catch()方法则只允许你绑定拒绝处理函数。

    你能用多种方式将多个 Promise 串联在一起,并在它们之间传递信息。每个对 then() 的调用都创建并返回了一个新的 Promise ,在前一个 Promise 被决议时,新Promise也会被决议。Promise链可被用于触发对一系列异步事件的响应。你还能使用 Promise.race() 与Promise.all() 来监视多个 Promise 的进程,并进行相应的响应。

    组合使用生成器与 Promise 会让异步任务运行得更容易,这是由于Promise提供了异步操作可返回的一个通用接口。这样你就能使用生成器与 yield 运算符来等待异步响应,并作出适当的应答。

    相关文章

      网友评论

          本文标题:ES6之Promise

          本文链接:https://www.haomeiwen.com/subject/whcbnctx.html