zoukankan      html  css  js  c++  java
  • Promise 入门与使用

    Tags: ECMAScript6

    参考资料

    Promise最初被提出是在 E语言中, 它是基于并列/并行处理设计的一种编程语言。

    概念

    ES6规定,Promise对象是一个构造函数,用来生成Promise实例。

    规范:Promises -> Promises/A -> Promises/A+

    状态

    Promise

    Promise实例生成以后处于pending状态,可以用then方法分别指定Resolved状态和Reject状态的回调函数。

    ES6 Promise 使用

    API

    • Promise.prototype.constructor
    • Promise.prototype.then
    • Promise.prototype.catch
    • Promise.all
    • Promise.race
    • resolve
    • reject

    基本用法

    var promise = new Promise(function (resolve, reject) {
        setTimeout(function () {
            resolve("success");
        }, 500);
        //reject(error);
    });
    
    promise
            .then(function (value) {
                //success
                console.log(value);
                return "over"
            }, function (value) {
                //error
                console.log(value);
            });
    
    console.log("hello");
    
    //"hello"
    //"success"
    

    链式调用

    then方法执行后会返回另一个promise,它的状态会传递给下一个then,如果没有显示的在回调函数中指定返回的promise对象,那么引擎会帮你生成一个promise并且执行其resolve方法,并且把你的回调函数传入其中。

    function asynchData (msg) {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                resolve(msg);
            }, 100);
        });
    }
    
    asynchData("step1")
            .then(function (value) {
                //success
                console.log(value);
                return asynchData("step2")
            })
            .then(function (value) {
                console.log(value);
            })
    
    //"step1"
    //"step2"
    
    asynchData("step2")
            .then(function (value) {
                //success
                console.log(value);
                return "success";
            })
            .then(function (value) {
                console.log(value);
            })
    //"step1"
    //"success"
    

    本身then、catch方法默认的返回是一个新的Promise对象

    function asynchData (msg) {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                resolve(msg);
            }, 100);
        });
    }
    
    var stepOne = asynchData("stepone");
    var stepTwo = stepOne.then(function (val) {
        console.log(val);//stepone
    });
    var stepThree = stepTwo.then(function (val) {
        console.log(val);//undefined
    });
    var stepThree2 = stepTwo.then(function (val) {
        console.log(val);//undefined
    });
    var catchStep = stepThree.catch(function (err) {
        console.log(err);
    });
    
    console.log(stepTwo instanceof Promise);//true
    console.log(stepThree instanceof Promise);//true
    console.log(stepThree2 instanceof Promise);//true
    console.log(catchStep instanceof Promise);//true
    

    error处理:catch

    其实catch是then(null, function(){...})的别名,实质上是相等的。注意一点,没有使用catch方法指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应。所以为了不给自己找麻烦尽量编写catch方法

    function asynchData (msg) {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                //Promise指定在下一轮“事件循环”再抛出错误,结果由于没有指定catch语句,就冒泡到最外层,成了未捕获的错误。
                throw new Error('async error!');
            }, 1000);
    
            throw new Error('error!');
        });
    }
    
    asynchData("step1")
            .then(function (value) {
                //success
                console.log(value);
            })
            .catch(function (err) {
                console.log(err);
                //如果Promise状态已经变成resolved,再抛出错误是无效的。
                //Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
            });
    
    //"Error: error!"
    
    asynchData("step2")
            .then(function (value) {
                //success
                console.log(value);
            })
            .then(null, function (err) {
                console.log(err);
            });
    
    //"Error: error!"
    

    这里有一个要注意的点:如果你一旦指定catch方法或者你在then方法里指定了reject方法,那么你指定的catch方法会捕获住异常,并且异常不再继续传递下去,无论你在catch里返回什么!除非catch方法里还有报错、或者返回一个reject状态的promise

    function asynchData (msg) {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                reject(msg);
            }, 100);
        });
    }
    
    asynchData("I am error")
            .then(function () {
                //resolve callback
            }, function (err) {
                //reject callback
                console.log(err + "from reject callback")
            })
            .catch(function (err) {
                //err callback
                console.log(err + " from catch callback");//catch callback无法执行,因为上一个then已经指定了reject处理方法
            })
    
    // I am errorfrom reject callback
    
    asynchData("I am error too")
            .then(function () {
                //resolve callback
            }, function (err) {
                //reject callback
                console.log(err + "from reject callback");
                throw new Error("I from reject callback error");
            })
            .catch(function (err) {
                //err callback
                console.log(err + " from catch callback");
                //catch callback会被执行,并且接收的错误是从上一个reject方法返回的
                //上一个then方法抛出异常,then返回一个reject状态的promise,并且被下一个catch方法捕获住
            })
    
    //I am error toofrom reject callback
    //Error: I from reject callback error from catch callback
    

    同步or异步

    试想下如果让你写一个api,其中有一个参数是callback形式传入,那么方法体内该是以何种形式执行callback呢?是同步呢还是异步执行呢?为了保持API的统一,我们定义callback在方法里都是以异步方式执行的。

    关于这个问题,在 Effective JavaScript 的 第67项 不要对异步回调函数进行同步调用 中也有详细介绍。

    绝对不能对异步回调函数(即使在数据已经就绪)进行同步调用。

    如果对异步回调函数进行同步调用的话,处理顺序可能会与预期不符,可能带来意料之外的后果。

    对异步回调函数进行同步调用,还可能导致栈溢出或异常处理错乱等问题。

    如果想在将来某时刻调用异步回调函数的话,可以使用 setTimeout 等异步API。

    Effective JavaScript
    — David Herman

    了避免同时使用同步、异步调用可能引起的混乱问题,Promise在规范上规定 Promise只能使用异步调用方式。

    var promise = new Promise(function (resolve) {
        console.log("inner promise"); // 1
        resolve(42);
    });
    promise.then(function (value) {
        console.log(value); // 3
    });
    console.log("outer promise"); // 2
    
    // inner promise
    // outer promise
    // 42
    

    Promise保证了每次调用都是以异步方式进行的,所以我们在实际编码中不需要调用 setTimeout 来自己实现异步调用。

    多个promise:all

    function asynchData (msg, toReject) {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                if (toReject) {
                    reject(msg + " failure!!!");
                } else {
                    resolve(msg);
                }
            }, 100);
        });
    }
    
    Promise.all([asynchData("step1"), asynchData("step2"), asynchData("step2")]).then(function (value) {
        console.log(value);//["step1", "step2", "step2"]
    });
    
    Promise.all([asynchData("step1", true), asynchData("step2", true), asynchData("step2")]).then(
            function (value) {
                console.log(value);//["step1", "step2", "step2"]
            },
            function (value) {
                console.log(value);//step1 failure!!!
                //之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值
            }
    );
    

    处理reject

    function asynchData (msg, toReject) {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                if (toReject) {
                    reject(msg + " failure!!!");
                } else {
                    resolve(msg);
                }
            }, 100);
        });
    }
    
    //之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的回调函数
    Promise.race([asynchData("step1"), asynchData("step2"), asynchData("step2")]).then(function (value) {
        console.log(value);//"step1"
    });
    

    一些例子

    我们定义A、B、C三个方法,并且都是异步的。我们希望A成功后执行B,失败执行C,B失败后执行C。想想改如何实现呢?

    function asynchData (msg, toFail) {
        return new Promise(function (resolve, reject) {
            console.log(msg);
            if (toFail) {
                reject();
            } else {
                resolve();
            }
        });
    }
    
    asynchData("A")
            .then(function () {
                return asynchData("B");
            })
            .then(null, function () {
                asynchData("C")
            });
    

    这样写是不是就达到目的了?

    Deferred & Promise 关系

    我们经常见到jquery.Deferred,但是和Promise有什么关系呢?Deferred和Promise不同,它没有共通的规范,每个Library都是根据自己的喜好来实现的。

    • Deferred 拥有 Promise
    • Deferred 具备对 Promise的状态进行操作的特权方法

    相信我们使用promise后会给我们带来耳目一新的感觉,减少我们的callback hell的出现频率,大大的增强我们代码的可维护性!

  • 相关阅读:
    环境是如何建立的 启动文件有什么
    环境中存储的是什么
    串行 并行 异步 同步
    TPC-H is a Decision Support Benchmark
    进程通信类型 管道是Linux支持的最初Unix IPC形式之一 命名管道 匿名管道
    删除环境变量
    14.3.2.2 autocommit, Commit, and Rollback 自动提交 提交和回滚
    14.3.2.2 autocommit, Commit, and Rollback 自动提交 提交和回滚
    14.3.2.1 Transaction Isolation Levels 事务隔离级别
    14.3.2.1 Transaction Isolation Levels 事务隔离级别
  • 原文地址:https://www.cnblogs.com/xiaoniuzai/p/6534374.html
Copyright © 2011-2022 走看看