zoukankan      html  css  js  c++  java
  • 谈谈promise

       最近在看《你不知道的javascript中卷》,发觉作者花了基本一半的篇幅去讲异步和promise,觉得有必要总结一下。

     其实本文的目的是想手写一个Promise的,无奈总结着总结着发觉篇幅有点长,因此只好一分为二,先介绍promise的用法,知道怎么用,我们才知道怎么写,所以把手写一个promise的任务放到了下一篇文章当中。

      当然,网上有很多关于promise的文章,都可以参考参考,有误之处,欢迎之处。

    什么是Prmoise

      promise是ES6新增的一个特征,它已被列入ES6的正式规范中

      Promise对象可以理解为一次执行的异步操作,使用promise对象之后可以使用一种链式调用的方式来组织代码;让代码更加的直观。也就是说,有了Promise对象,就可以将异步操作以同步的操作的流程表达出来,避免了层层嵌套的回调函数。

    示例:未使用promise,回调必须层层嵌套

    复制代码
    $.ajax(url1, function(data1){
        // do something...
        $.ajax(url2, function(data2){
            // do something...
            $.ajax(url3, function(data3){
                // do something...
                done(data3); // 返回数据
            })
        });
    });
    复制代码

     如果有多个嵌套,导致代码不够直观,而且如果几个操作之前没有前后顺序之分,需要等待上一个操作完成才可以进行下一个操作,造成不必要的等待

    promise就是为了解决这些问题而产生的。

    Promise对象的特点:

        1、对象的状态不受外界影响。

      Promise对象代表一个异步操作,有三种状态

    • pending(执行中)
    • Resolved(成功,又称Fulfilled)
    • rejected(拒绝)

    其中pending为初始状态,fulfilled和rejected为结束状态(结束状态表示promise的生命周期已结束)。

    promise只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态.。

       2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。

     Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected

    pending->fulfilled,pending->rejected。

    只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果

     

    Promise对象的缺点:

    1、无法取消Promise,一旦新建它就会立即执行,无法中途取消。

    2、如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

    3、当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

    promise兼容性

    除了IE这种古老的浏览器和一些低版本的安卓外,现代浏览器支持还是挺好的,所以我们可以在谷歌的控制台直接测试我们的代码

    Promise的使用

    先提前说明一下,下面的代码示例,都可以复制到谷歌的控制台就行测试!!

    1、基本用法:

    (1)、首先我们new一个Promise,将Promise实例化

    (2)、然后在实例化的promise可以传两个参数,一个是成功之后的resolve,一个是失败之后的reject

    (3)、Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数

    代码如下:

    复制代码
    var promise = function(isReady){
        return new Promise(function(resolve, reject){
            // do somthing, maybe async
            if (isReady){
              return resolve('hello world');
            } else {
              return reject('failure');
            }
        });
    }
     
    //Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。
    promise(true).then(function(value){
        // success,这里是resolve的回调函数
        console.log(value);  //hello world
    }, function(err){
        // failure,这里是reject的回调函数
        console.log(err)
    })
    复制代码

    上述代码是执行成功,返回hello world,如果想测试一下失败后的返回值,可以在promise(true).then...这里改为 promise(false).then...即可 

    2、链式操作

    也许你会说,Promise只是简化层层回调的写法而已吧,其实不然,它的精髓是通过维护状态、传递状态的方式来使回调方式能够及时的调用,因此,相比于callback,它更灵活,更简单。下面我们来看看Promise的链式操作:

    复制代码
    makePromise1()
    .then(function(value){
        console.log(value);
        return makePromise2();
    })
    .then(function(value){
        console.log(value);
        return makePromise3();
    })
    .then(function(value){
        console.log(value);
    });
    
    function makePromise1(){
        var p = new Promise(function(resolve, reject){
            //异步操作
            setTimeout(function(){
                console.log('异步任务1');
                resolve('异步任务1传过来的值');
            }, 2000);
        });
        return p;            
    }
    function makePromise2(){
        var p = new Promise(function(resolve, reject){
            //异步操作
            setTimeout(function(){
                console.log('异步任务2');
                resolve('异步任务2传过来的值');
            }, 2000);
        });
        return p;            
    }
    function makePromise3(){
        var p = new Promise(function(resolve, reject){
            //异步操作
            setTimeout(function(){
                console.log('异步任务3');
                resolve('异步任务3传过来的值');
            }, 2000);
        });
        return p;            
    }
    复制代码

    上面的代码中,我们有三个异步操作,makePromise1,makePromise2,makePromise3。其中第二个和第三个依次执行,也就是上一个操作完成之后才可以进行。

    输出的值为:

    异步任务1
    异步任务1传过来的值
    异步任务2
    异步任务2传过来的值
    异步任务3
    异步任务3传过来的值

    3、Promise的catch方法

    复制代码
    var promise = function(isReady){
        return new Promise(function(resolve, reject){
            // do somthing, maybe async
            if (isReady){
              return resolve('hello world');
            } else {
              return reject('failure');
            }
        });
    }
    promise(true)
    .then(function(value){
        console.log('resolved');
        console.log(value);
        console.log(haha); //此处的haha未定义
    })
    .catch(function(error){
        console.log('rejected');
        console.log(error);
    });
    复制代码

         catch 方法是 then(onFulfilled, onRejected) 方法当中 onRejected 函数的一个简单的写法,也就是说可以写成 then(fn).catch(fn),相当于 then(fn).then(null, fn)

         使用 catch 的写法比一般的写法更加清晰明确,其实可以类比成try/catch,这样,其中有报错的地方不会阻塞运行。比如定义了一个未定义haha,正常来说它上面的代码也不会运行,因为被这个报错阻塞了,有了catch,它上面的代码可以正常运行下去:

    控制台打印出来的东西:

    resolved
    hello world
    rejected
    ReferenceError: haha is not defined(…)

    4、promise.all方法

      Promise.all 可以接收一个元素为 Promise 对象的数组作为参数,当这个数组里面所有的 Promise 对象都变为 resolve 时,该方法才会返回。

    代码示例:

    复制代码
    var p1 = new Promise(function (resolve) {
        setTimeout(function () {
            resolve("第一个promise");
        }, 3000);
    });
    
    var p2 = new Promise(function (resolve) {
        setTimeout(function () {
            resolve("第二个promise");
        }, 1000);
    });
    
    Promise.all([p1, p2]).then(function (result) {
        console.log(result); // ["第一个promise", "第二个promise"]
    });
    复制代码

         上面的代码中,all接收一个数组作为参数,p1,p2是并行执行的,等两个都执行完了,才会进入到then,all会把所有的结果放到一个数组中返回,所以我们打印出我们的结果为一个数组。

      值得注意的是,虽然p2的执行顺序比p1快,但是all会按照参数里面的数组顺序来返回结果。all的使用场景类似于,玩游戏的时候,需要提前将游戏需要的资源提前准备好,才进行页面的初始化。

    5、promise.race方法

          race的中文意思为赛跑,也就是说,看谁跑的快,跑的快的就赢了。因此,promise.race也是传入一个数组,但是与promise.all不同的是,race只返回跑的快的值,也就是说result返回比较快执行的那个。

    复制代码
    var p1 = new Promise(function (resolve) {
        setTimeout(function () {
            console.log(1);
            resolve("第一个promise");
        }, 3000);
    });
    
    var p2 = new Promise(function (resolve) {
        setTimeout(function () {
            console.log(2);
            resolve("第二个promise");
        }, 1000);
    });
    
    Promise.race([p1, p2]).then(function (result) {
        console.log(result); 
    });
    
    // 结果:
    // 2
    // 第二个promise
    // 1
    复制代码

    可以看到,传的值中,只有p2的返回了,但是p1没有停止,依然有执行。

    race的应用场景为,比如我们可以设置为网路请求超时。写两个promise,如果在一定的时间内如果成功的那个我们没有执行到,我们就执行失败的那个,这里不再举例子,可以看看阮一峰的ES入门。

    ES6的介绍就到这里了,下一篇文章我们来手写一个promise

  • 相关阅读:
    vue开发chrome扩展,数据通过storage对象获取
    Vue手动集成less预编译器
    Google Translate寻找之旅
    Javascript Range对象的学习
    Javascript Promises学习
    SublimeText 建立构建Node js系统
    We're sorry but demo3 doesn't work properly without JavaScript enabled. Please enable it to continue.
    npm安装包出现UNMET DEPENDENCY报错
    (转载)命令行说明中格式 尖括号 中括号的含义
    Linux重启网卡服务Failed to start LSB: Bring up/down networking.
  • 原文地址:https://www.cnblogs.com/aeexiaoqiang/p/6529288.html
Copyright © 2011-2022 走看看