美文网首页Web前端之路让前端飞技术干货
ECMAScript6基础学习教程(八)Promise

ECMAScript6基础学习教程(八)Promise

作者: 娜姐聊前端 | 来源:发表于2017-04-20 18:38 被阅读144次

    JavaScript被设计为单线程(webWoker可以处理多线程),利用事件轮询机制,可以模拟出多线程效果,也就是异步操作,而回调函数callback是事件轮询调用的目标方法。

    但是,通过回调函数处理异步事件有很多不确定性,并且容易陷入“回调地狱”-嵌套太深。于是,Promise概念被提出,并且很多JavaScript框架(比如JQuery)支持的异步API都基于Promise理念构建的。

    1.什么是Promise?

    Promise是一个对象,用来传递异步操作的信息,它代表了某个未来时刻才知道结果的事件,并且这个事件提供统一API接口。

    2. Promise对象

    Promise原型对象提供的主要方法有:

    //添加状态改变时的回调函数
    Promise.prototype.then(resolvedFunc, rejectedFunc) 
    //响应rejected状态的promise(如果前面有错误抛出,会产生一个rejected状态的promise)
    //相当于promise.then(null, rejectedFunc)
    Promise.prototype.catch(rejectedFunc) 
    

    参考一个标准的Promise实例:

    var promise = new Promise(function(resolve, reject){
      // 你的代码---pending状态
      if (isSuccessful) {
        resolve(value); // 成功
      }
      else {
        reject(error); // 失败
      }
    // 这里的代码永远不会被运行
    });
    
    promise
    .then(
      function(value){//resolved时调用}, 
      function(error){// rejected时调用})
    .catch(function(error){//有错误抛出时调用});
    

    promise对象有如下特点:

    1. 可以利用promise对象创建一个异步操作。
    2. 有三种状态:pending, resolved和rejected。异步代码运行时为pending,运行后的结果只会是两种:成功-resolved,或者失败-rejected。状态变化是单行流动,不可逆转。
    3. 在一个promise里,resolve或者reject方法只会被调用一次。
    4. resolve()/reject()可以利用参数传递数据,但是,只支持传递第一个参数。也就是说,promise决议只能传递单个值/对象。因此,实际应用中,需要将多个值封装在一个对象中传递
    5. then()和catch()函数都会默认返回一个promise对象。
    6. 如果没有给then()传递函数作为完成处理函数参数,还是会有替代的默认处理函数,并且,该默认函数会把接受到的值传递给下一个promise对象。
    getPromise(40, true).
        then(null,null).then(function (value) {
        console.log("resolved:"+value);
    });
    // 打印:resolved:40
    // 可见,如果不设置then的处理函数参数,resolved值40一直会被传递下去。
    

    3. 一个Promise实例

    下面是一个Promise例子,参考注释。
    创建promise的工厂方法:

    var getPromise = function (val, isSuccessful) {
        var promise = new Promise(function (resolve, reject) {
            setTimeout(function () {
                if (isSuccessful) {
                    // 决议成功,回调then()的第一个函数参数
                    resolve(val); 
                }
                else {
                    // 决议失败,回调then()的第二个函数参数
                    reject(new Error("oh, error!")); 
                }
            }, 0);
        });
        return promise;
    };
    

    第一次测试(连续调用两次promise):

    getPromise(30, true).then((value) => {
        console.log("the first resolved status: " + value);
        // 返回一个promise对象,该promise决议结果会决定下一个then()函数应该调用哪个回调函数
        // 如果不显性返回promise对象,ES6会默认创建一个空值promise对象最为返回值
        return getPromise(20, true);
    }, (error) => {
        console.log("the second rejected status: " + error);
    }).then((value) => {
        console.log("the second resolved status: " + value);
        // 一个rejected状态的promise对象被返回
        //由于后续没有then(),因此catch函数捕获错误状态
        throw new Error('create a error!');
    }, (error) => {
        console.log("the second rejected status: " + error);
    }).catch((error) => {
        console.log("Catch: " + error);
    });
    
    //运行结果:
    the first resolved status: 30
    the second resolved status: 20
    Catch: Error: create a error!
    

    第二次测试(多加一个then调用):

    getPromise(30, true).then((value) => {
        console.log("the first resolved status: " + value);
        return getPromise(20, true);
    }, (error) => {
        console.log("the second rejected status: " + error);
    }).then((value) => {
        console.log("the second resolved status: " + value);
        // 一个rejected状态的promise对象被返回
        //由于后续有then(),因此then函数的第二个回调函数被运行
        throw new Error('create a error!');
    }, (error) => {
        console.log("the second rejected status: " + error);
    }).then((value) => {
        console.log("the third resolved status: " + value);
    }, (error) => {
        console.log("the third rejected status: " + error);
    }).catch((error) => {
        console.log("Catch: " + error);
    });
    
    // 运行结果:
    the first resolved status: 30
    the second resolved status: 20
    the third rejected status: Error: create the first error!
    

    第三次测试(修改getPromise函数):

    var getPromise = function (val, isSuccessful) {
        var promise = new Promise(function (resolve, reject) {
             if (isSuccessful) {
                    resolve(val);
                    //resolve之后抛出错误,是不会被捕获的
                    throw new Error('error, error, error!');
                }
                else {
                    reject(new Error("oh, error!"));
                }
        });
        return promise;
    };
    // 测试1和测试2的运行结果不会改变
    

    从上面的例子可以看到,可以用同步书写方式连续调用多个异步请求。并且,Promise还提供了静态函数帮助解决更复杂的异步编程场景。

    4. Promise静态方法

    Promise提供的静态方法有:

    Promise.all([promise1, promise2 [,promiseN]])
    Promise.race([promise1, promise2 [,promiseN])
    Promise.resolve()
    Promise.reject()
    
    (1) Promise.all()

    将多个promise实例包装成一个新的promise对象,只有多个promise的状态都为resolved,Promise.all()的状态才会变为resolved。
    继续上面的例子,测试如下:

    Promise.all([
        getPromise(20, true),
        getPromise(30, true), 
        getPromise(40, true)])
        .then(function (value) {
            console.log(value);
        });
    // 输出为:[ 20, 30, 40 ]
    

    每个Promise实例的resolved值都会暂存在一个数组里,最后,该数组被传递到Promise.all()的resolved回调函数。

    (2) Promise.race()

    将多个promise实例包装成一个新的promise对象,只有第一个promise状态为resolved时,Promise.race()的状态才变为resolved

    并且,第一个promise的值会传递给Promise.race()。

    基于上面例子继续测试:

    Promise.race([
        getPromise(20, true),
        getPromise(30, false),
        getPromise(40, false)])
        .then(function (value) {
            console.log(value);
        }, function (error) {
            console.log(error);
        });
    //输出为: 20
    
    Promise.race([
        getPromise(20, false),
        getPromise(30, true),
        getPromise(40, false)])
        .then(function (value) {
            console.log(value);
        }, function (error) {
            console.log(error);
        });
    // 输出为: [Error: oh, error!]
    
    (3) Promise.resolve()

    该方法会返回一个Promise对象,情况分为两种:

    • 如果目标对象不是Promise对象,该方法会创建一个Promise对象
    • 如果目标对象本身就是Promise对象,该方法会将这个Promise对象直接返回
    // p2和p1行为完全一样
    var p1 = new Promise(function(resolve, reject){
      resolve(40);
    });
    var p2 = Promise.resolve(40);
    // 向Promise.resolve()传递一个Promise对象,则直接返回这个对象
    var p3 = Promise.resolve(p2);
    console.log(p2===p3); // true
    
    (4) Promise.reject()

    返回一个新的Promise实例,状态为rejected:

    var p = new Promise(function(resolve, reject){
      reject("error");
    }); 
    
    //可以用 Promise.reject()快速创建promise对象,状态为rejected
    var p = Promise.reject("error");
    p.then(null, function(error) {
    // 回调函数被调用
    });
    

    微信公众号:

    相关文章

      网友评论

        本文标题:ECMAScript6基础学习教程(八)Promise

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