• promise和async/await的区别


    两者都是做异步处理的, 使异步转为同步,目的都是为了解决异步回调产生的“回调地狱”。
    同步: 顺序执行,始终和前文保持在一个上下文,可以快速捕获及处理异常。由于js是单线程,当代码量多时容易造成阻塞,耗费时间。
    异步: 由浏览器(多线程)提供,解决阻塞,异步任务始终在同步任务全部执行完毕后才执行,像回调函数,ajax、setTimeout。提高了执行效率,节省时间,但是会占用更多资源,不利于对进程控制。
    btw… 异步任务其实是可以和同步任务同时进行的,但是异步任务的回调函数(真正的异步)一定是在同步任务全部执行完毕后执行的,因为异步回调任务一定是在js线程中完成的。即异步操作在浏览器线程,而异步执行回到js线程。
    回调地狱: 当许多功能连续调用,回调函数层层嵌套,形成一个三角形,造成可读性差,代码可维护性可迭代性差,可扩展性差。

    一、什么是promise(承诺)
    Promise是ES6中的一个内置对象,(实际是一个构造函数,通过函数可以创建一个promise对象),作用为解决异步调用问题
    特点:
    ①、三种状态:pending(进行中)、resolved(已完成)、rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都不能改变这个状态。

    ②、两种状态的转化:其一,从pending(进行中)到resolved(已完成)。其二,从pending(进行中)到rejected(已失败)。只有这两种形式的转变。

    ③、缺点:在pending阶段,无法取消状态,且无法判断pending的进度(是刚开始还是即将结束)

    二、使用promise
    若需要使用带setTimeout()。其在Chrome中可以传多个参数

    setTimeout(function (a, b) {
        console.log(a + b);
    }, 1000, 20, 50);  // 70

    创建一个promise实例:

    var mypromise = new Promise( ( resolve,reject )=>{  //构造函数new创建对象,函数必须有 
        // do something...
        If( /*异步操作成功*/ ){
            resolve(value);  // pending---resolve
        }else{
            reject(error);  //pending---reject
        }
    } )
    //  后续操作:执行回调函数.then()方法来操作成功或失败要操作的事情
    mypromise .then( (value)=>{
        // success
    }, (error)=>{
        // failure
    } )

    箭头函数只是初始化promise对象,并且接受了resolve和reject两个函数作为参数。注意if语句不是必要的,只是要表达若异步成功,就调用resolve函数,状态转化,并将value值传递下去,因为promise还有一个.then()方法,即成功(或失败)后的一些操作,这也是resolve和reject内置函数存在的意义。反之若异步失败亦是。

    举例: 使用构造函数创建对象

    let p = new Promise(function(resolve, reject) { 
    // Promise() 就是一个构造函数,通过new创建了p对象实例
        console.log('i am promise');
    	var a = 2,b = 1;
        if(a>b){
    		resolve(a);
        }else{
    		reject(error)
    	}
    });
    p.then(function(value) {  // 执行异步回调函数
    	console.log('resolved.');
    },function(error){
    	console.log('reject')
    });
    console.log('Hi!');
    //  i am promise;   Hi;   resolved;   //可以看出promise是异步的
    

     

    三、promise.prototype.then()

    then()作用:是为promise实例添加状态发生改变时的回调函数。第一个参数(必选)是resolve状态的回调,第二个参数(可选)是reject状态回调的函数
    then()方法是promise原型上定义的方法。输出promise.prototype可看到内置对象
    then()方法支持链式调用,即上一个方法调用后的结果会传给下一个方法。
    等同于:

    mypromise.then(function(data) {
    	console.log('Contents: ' + data);
    }).then( function(error) {
    	console.error('出错了', error);
    } )

    第一个回调函数完成后,会将结果作为参数,传递到下一个回调函数。

    四、promise.prototype.catch()
    建议then()不要使用第二个参数,而使用catch()

    Promise.then( function(data){ // 建议
    	//success
    } ).catch( function(err){
    	//error
    } )

    因为catch() 方法返回的还是一个promise对象,后续可以继续使用then()进行链式调用。
    resolve — 对应then。只有调用了resolve才会触发then方法的回调
    reject — 对应catch。只有调用了reject才会触发catch方法的回调

    五、promise.all()
    作用:将多个promise实例包装成一个新的promise实例
    Var arr = [1,2,3]
    Var p = promise.all(arr).then(…)
    其中数组中1,2,3都是promise对象实例。若不是,就会先调用下面讲到的promise.resolve()方法,将参数先转为实例,再下一步处理。
    p的状态(成功或失败再执行then回调) 由数组的所有实例对象决定:
    1、只有所有实例对象都是resolve,p的状态才resolve。然后返回值也是数组,传递给p的回调函数;
    2、当有一个实例被reject了,p状态就会是reject。此时第一个被reject的实例返回值,会传递给p的回调函数。

    举例:

    var p= [1,2,3,4,5,6].map( function(i){
    	console.log(i);
    } )
    promise.all(p).then(...).catch(...)
     

    通过数组map生成6个实例对象,然后作为参数传递promise.all(),只有当全部为resolve时才会调用then()方法,否则调用catch()方法。

    六、promise.race()
    同五。也是将多个promise实例包装成一个新的promise实例。状态亦是。
    Var p = promise.race( [1,2,3] )

    七、promise.resolve()
    将现有的对象转化为promise对象。看参数的不同分4种情况…

    八、promise.reject()
    promise.reject(reason)方法也会返回一个新的promise实例,该实例状态为reject。

    九、理解promise
    其作用就是如果前面的代码非常耗时,就会阻塞后面要执行的代码,所以有异步操作。
    举例:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>testsettimeout</title>
    </head>
    <body>
        <div class="wrap"></div>
        
        <script>
        let promise = new Promise(function(resolve, reject) {
          console.log('Promise! 我是Promise对象里的函数,我最早出现是因为我要给后面一个耗时的家伙提供数据a');
          var a = 20;
          resolve(a);
        });
    
        promise.then(function(value) {
          console.log('哈哈哈,我得到数据a了,要开始执行喽。我是一个非常耗时的操作,依赖前面的数据,但是我想快一点执行,这有利于用户体验,所以别把我放在后头啊;我被放在了一个新的线程上,不会阻塞别人的');
          for (var i = 0; i < 1000000; i++) {
          	var li = document.createElement("li");
            document.querySelector(".wrap").appendChild(li);
          }
          console.log("执行完毕");
          
        });
    
        console.log('Hi! 我是什么都不依赖的程序,但我也想快一点执行,不能委屈我啊');
        </script>
    </body>
    </html>
    
    // 'Promise! 我是Promise对象里的函数...
    // Hi! 我是什么都不依赖的程序...
    // 哈哈哈,我得到数据a了,要开始执行喽...
    // 执行完毕
    

      

    在new promise里的函数是立即执行函数,执行顺序:
    (匿名函数—Promise!…)-----(若还有同步任务 —Hi! …)—紧接着是promise.then回调函数的执行。所以promise.then()函数才是真正的异步执行。

    Async await
    Async搭配await是ES7提出的,基于promise实现,也是非阻塞的异步转同步,让代码更加语义化,更有可读性。
    Await函数不能单独使用(无效),事实上async函数会返回一个promise对象,可以使用then函数添加回调。执行函数时,一旦遇到await函数就会先返回一个promise对象,等到异步操作完成,再去执行后面的语句,若await异步操作出错,就相当于async返回的promise对象被reject了。

    async函数在function前面有个async作为标识,意思就是异步函数,里面有个await搭配使用,await是等待的意思,那么它等待什么呢,它后面跟着什么呢?其实它后面可以放任何表达式,不过我们更多的是放一个返回promise 对象的表达式,它等待的是promise 对象的执行完毕,并返回结果。每到await的地方就是程序需要等待执行后面的程序,语义化很强,下面总结一下async函数的特点:
    1. 语义化强
    2. 里面的await只能在async函数中使用
    3. await后面的语句可以是promise对象、数字、字符串等
    4. async函数返回的是一个Promsie对象
    5. await语句后的Promise对象变成reject状态时,那么整个async函数会中断,后面的程序不会继续执行
    基于上面的async的特点,我们会用到异常捕获机制-----try…catch…

    举例:Async搭配await发送异步请求
    现在写一个函数,让它返回promise 对象,该函数的作用是2s 之后让数值乘以2

    // 2s 之后返回双倍的值
    function doubleAfter2seconds(num) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(2 * num)
            }, 2000);
        } )
    }
    // 再写一个async 函数,从而可以使用await 关键字, await 后面放置的就是返回promise对象的一个表达式,所以它后面可以写上 doubleAfter2seconds 函数的调用
    async function testResult() {
        let first = await doubleAfter2seconds(30);
        let second = await doubleAfter2seconds(50);
        let third = await doubleAfter2seconds(30);
        console.log(first + second + third);   // 220
    }
    testResult();  // 调用
    console.log('先执行');
     

    6秒后,控制台输出220, 我们可以看到,写异步代码就像写同步代码一样了,再也没有回调地狱了。

      1. 代码执行过程:调用testResult函数,然后再里面遇到了await函数,要等待,代码就执行到这,等后面的promise对象执行完毕,拿到promise resolve的值进行返回,然后await才会继续向下执行。
      2. 具体到 我们的代码, 遇到await 之后,代码就暂停执行了, 等待doubleAfter2seconds(30) 执行完毕,doubleAfter2seconds(30) 返回的promise 开始执行,2秒 之后,promise resolve 了, 并返回了值为60, 这时await 才拿到返回值60, 然后赋值给result, 暂停结束,代码继续执行,执行 console.log语句。
      3. Async/await相对来说更简洁,不用写很多的then(),不用匿名函数处理。
        让try/catch可以同时处理同步和异步处理。在promise中就无法处理,要使用.catch()方法,代码冗余。
      4. 这里强调一下等待,当js引擎在等待promise resolve 的时候,它并没有真正的暂停工作,它可以处理其它的一些事情,如果我们在testResult函数的调用后面,console.log 一下,你发现 后面console.log的代码先执行。
  • 相关阅读:
    触摸屏测试:Tslib
    Ubuntu:我不小心把/var/lock文件夹给删了
    驱动开发学习笔记. 0.02 基于EASYARM-IMX283 烧写uboot和linux系统
    驱动开发学习笔记. 0.01 配置arm-linux-gcc 交叉编译器
    驱动开发学习笔记.0.00 从拿到一块开发板开始
    利用联合体通过串口收发浮点数
    stm32 MDK5软件仿真之查看io口输出
    ListView 类
    INotifyPropertyChanged 接口
    ItemsControl 类绑定数据库
  • 原文地址:https://www.cnblogs.com/DrcProgrammingCool/p/13763676.html
Copyright © 2020-2023  润新知