zoukankan      html  css  js  c++  java
  • Promise、async/await、Generator 异步解决方案

    参考: https://www.cnblogs.com/CandyManPing/p/9384104.html  或  https://www.jianshu.com/p/fe0159f8beb4(推荐这个,比较清晰)


     Promise :https://www.jianshu.com/p/fe0159f8beb4 或 https://www.runoob.com/w3cnote/es6-promise.html

    1、Promise 对象 :Promise 实例 只是一个对象 不是方法,参数是一个回调函数,创建对象时立即执行。

    const p2 = new Promise(function(resolve,reject){  
        resolve('success3'); 
        reject('reject'); // pending 状态改变,就不会再变
    });
    console.log(p2)   // Promise {<resolved>: "success3"}

      如果要实现  调用某个函数后 变成一个 Promise 对象,只要这个函数  return 出来一个promise 对象就可以了。

    function ajax(URL) {
        return new Promise(function (resolve, reject) {   // return 一个 promise对象
            var req = new XMLHttpRequest(); 
            req.open('GET', URL, true);
            req.onload = function () {
            if (req.status === 200) { 
                    resolve(req.responseText);   // pending 状态 变成 fulfilled(成功)
                } else {
                    reject(new Error(req.statusText)); // pending 状态 变成 rejected(失败)
                } 
            };
            req.onerror = function () {
                reject(new Error(req.statusText));
            };
            req.send(); 
        });
    }

    感悟:Promise 对象 和 XHR 对象 比较类似,他们本身只是一个对象。但是这个对象 有一个异步的方法,当这个对象内的某个条件改变才会触发这个异步的方法执行。

       Promise 对象内 的那个条件的变化是可以人为的控制的,但是XHR 对象的某个条件的变化不能人为控制,由请求状态决定。

    2、Promise.resolve()  :将现有对象转为 Promise 对象的快捷方式。(注意,这个不是Promise实例的方法,不要混为一谈。即 new PromisePromise.resolve() 都是创建Promise 对象的方法)

       Promise.resolve() 的参数 分 4 种情况:https://blog.csdn.net/ixygj197875/article/details/79183843

     a、不带有任何参数,直接返回一个resolved状态的 Promise 对象。

        const p = Promise.resolve()
    
        p.then(res => {
          console.log(res) // undefined
        })

     b、传一个普通的对象,将普通对象 转为 Promise 对象

    let p1 =Promise.resolve({name:'xixi',age:'xxxx'});
    
    p1.then(result => {
        console.log(result);  // {name: "xixi", age: "xxxx"}
    });

        c、传一个 Promise 对象实例, Promise.resolve将不做任何修改、原封不动地返回这个实例。

        let p = new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve('success')
          }, 500)
        })
    
        let pp = Promise.resolve(p)
    
        pp.then(result => {
          console.log(result) // success
        })
    
        console.log(pp === p) // true

       d、传一个 thenable对象(thenable对象指的是具有then方法的对象),Promise.resolve方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。(一般不会使用这种情况的参数,这里不详细说明)

        let thenable = {
          then: function (resolve, reject) {
            resolve(42) // 这里 then函数返回的不是一个 Promise对象就不会执行下面那个then里面的函数
          }
        }
        let p1 = Promise.resolve(thenable)
        p1.then(function (value) {
          console.log(value) // 42
        })

    3、Promise.reject()  :快速的获取一个拒绝状态的 Promise 对象。(这个方法 和 Promise.resolve() 方法是一样功能。Promise 对象会有两个状态变化,Promise.reject()创建的对象就是执行catch中的函数)

       注意:Promise.reject() 后面没有 catch 函数就会报错的。Promise.resolve() 后面没有 then函数是 不会报错的。

    4、Promise.resolve().then()  的 执行顺序比 setTimeout(fn, 0) 先。同步程序肯定比 异步Promise 对象先执行。

    setTimeout(function () {
      console.log('three');
    }, 0);
    Promise.resolve().then(
    function () {   console.log('two'); });
    console.log(
    'one'); // one // two // three

    5、Promise 对象的回调函数(then或catch)中没有return ,执行后的 相当于 返回  没有参数的 Promise.resolve() 对象。

        var resolve = Promise.resolve('resolve')
          .then(res => {
            console.log('resolveSuc',res)
          })
          .catch(err => {
            console.log('resolveErr',err)
          })
        var reject = Promise.reject('reject')
          .then(res => {
            console.log('rejectSuc',res)
          })
          .catch(err => {
            console.log('rejectErr',err)
          })
    
        setTimeout(function () {
          console.log(resolve) // Promise {<resolved>: undefined}
          console.log(reject) // Promise {<resolved>: undefined}
        }, 0)

    6、Promise.reject() 对象 有多个 then 函数,只有一个catch 函数(任意位置),链式函数会先执行 catch 里面的函数,并且从这个 catch 开始继续执行下面的链式写法的函数。(Promise.resolve()同样的道理,从第一个then开始连续问下执行)

        Promise.reject('resolve')
        .then(res => {  console.log('sucess1', res) })
        .then(res => {  console.log('sucess2', res) })
        .catch(() => {  console.log('fail_1')
        })
        .then(res => {
          console.log('sucess5', res)
          return Promise.reject('resolve')
        })
        .then(res => {  console.log('sucess6', res) })
        .catch(() => {  console.log('fail_2')  })
        
        // fail_1
        // sucess5 undefined
        // fail_2

     7、promise对象then方法中,return 值 和returnPromise.resolve() 的区别:https://codeday.me/bug/20170630/32846.html 

      总结:他们的区别就是,return Promise.resolve('resolve') 或 return Promise.reject('reject') 返回一个promise对象,并且状态变成 resolve 或 reject。 如果返回普通类型的值,就直接作为参数传给下一个 then。

         return 普通值 和 returnPromise.resolve() 结果是一样的,没有区别。但是 和 return Promise.reject('')  就有区别了。   即返回 promise对象,下面执行哪个函数是根据 resolve 或 reject状态 有选择的执行的。


     Async-Await (这是 es8 的内容)  https://www.cnblogs.com/SamWeb/p/8417940.html

    1、async用于申明一个function是异步的。而 await 可以认为是async wait的简写,等待一个异步方法执行完成。(Async-Await 是 寄生于 Promise的)

    2、async 函数 执行后返回的是一个 promise 对象,而不是 普通函数具体的  返回值。(promise 对象需要通过 then或catch 添加回调函数的)。

        async function timeout () {
          return 'hello world'
        }
        console.log(timeout()) // Promise {<resolved>: "hello world"}
        console.log('虽然在后面,但是我先执行')

    3、await 只能在 async 定义的函数里面 使用,不能单独使用。实际上,await是强制把异步变成了同步。(await 后面可以放任何表达式,一般都是promise对象,因为放同步的表达式就没有 等待的意义了。)

    async getFaceResult () {
                    try { // 注意,这里使用try...catch 捕获 异常
                        let location = await this.getLocation(this.phoneNum);
                        if (location.data.success) {
                            let province = location.data.obj.province;
                            let city = location.data.obj.city;
                            let result = await this.getFaceList(province, city);
                            if (result.data.success) {
                                this.faceList = result.data.obj;
                            }
                        }
                    } catch(err) {
                        console.log(err);
                    }
                }

    4、async/await 的优势在于处理 then 链:https://www.jianshu.com/p/8a9bfc5128b4 

      个人见解:async/await 处理 嵌套请求真的很漂亮,没有回调地狱的困扰。

             但是 await 必须结合 try / catch 使用,否则 无法 捕获 await 后面 promise对象的错误,async函数就会中断操作。

    5、将 promise 对象的ajax请求变成  async/await的想法很简单:https://www.cnblogs.com/dyy-dida/p/11110003.html

    new Vue({
       el:"#app",
       created(){
          this.ajaxData();
       },
       mothods:{
          ajaxData(){
             const result = axios.get('/homeapp.do').then((res)=>{
                   console.log(res);
              })
          }
       }     
    }) 

    使用 async/await 后代码变成

    new Vue({
       el:"#app",
       created(){
          this.ajaxData();
       },
       mothods:{
          async ajaxData(){
             const result = await axios.get('/homeapp.do');
             console.log(result);
          }
       }     
    })

    6、async 函数前后的执行顺序:  参考链接

      a、 async 函数 和 普通函数一样,只有在执行到时 await 关键字时,才会让 async 函数后面的程序先执行。

      b、 async 函数 里面可以没有 await 关键字。这时 async 函数,就是一个普通函数。里面 有没有 异步 函数,和普通 函数中 有没有异步函数是一样的。

    async function foo() { 
    console.log(1);  // 和普通函数一样,执行到这里,下面碰到 await 关键字,才变成异步执行的程序
    await Promise.reject(3); 
    }
    
    foo().catch(console.log); 
    console.log(2);
    
    // 1
    // 2
    // 3

    个人体会 :1、Async-Await 使得 异步代码内的异步,可以同步执行。(简单理解,就是多个异步程序嵌套,只要通过 Async 告诉程序,最外围的一个函数是异步就可以了,里面的异步全部变成同步的执行。)

          这种 程序控制   在 某个请求 需要另一个请求返回的参数,这种多层请求嵌套的 时候 就非常有优势。

          2、promise 解决了回调函数不能 返回 数据的问题。因为promise是异步返回的数据不知道什么才有,所以基本没什么用。但是 await 的出现,使得 promise返回的数据可以进行使用了。(即异步回调函数的返回值可以控制什么时候使用了)

          3、Async-Await 相当于声明一个异步的程序空间,在这个空间中让异步的程序,同步执行。这样就不用再异步程序中嵌套回调函数了,全部都是同步的写法,并且增强是代码可读性。  https://www.cnblogs.com/yetianmao/p/8721884.html (这里的执行顺序,并不是想当然的那样,有时间在研究下


    Generator 生成器:    https://www.kunjuke.com/jiaocheng/33366/  或  https://www.ruanyifeng.com/blog/2015/04/generator.html

    1、yield / next 概念:https://www.jianshu.com/p/83da0901166f  或  https://blog.csdn.net/HHW223/article/details/106227524(推荐)

       yield:yield表达式 可以在生成器函数内部暂停代码的执行使其挂起。并且 yield 后面的 表达式  的值 会 返回给 调用它的 next() 函数。

       next :next()方法 启动生成器   以及 控制生成器的代码从暂停的位置开始继续往下执行。next 传入的参数,表示  上一个yield 表达式的返回值。

    function* gen(x){
      var y = yield x + 2;  // yield 后面的表达式 值,作为g.next() 对象中value的值
      return y;
    }
    
    var g = gen(1);
    g.next() // { value: 3, done: false }
    g.next(2) // { value: 2, done: true }     【这里的 传入的 参数2,作为 yield x+2  表达式的返回值】

    2、Generator + Promise + 执行器  实际 开发实践:

  • 相关阅读:
    树莓派使用记录 修改国内软件源《二》
    树莓派使用记录 安装系统《一》
    C# 委托 Action 实现代码执行时间日志记录
    微软 Visual Studio 离线下载
    项目框架搭建工具
    WebApi 重写 DefaultHttpControllerSelector 实现路由重定向
    开发相关网页收藏
    造SQL语句
    报错:Every derived table must have its own alias
    html
  • 原文地址:https://www.cnblogs.com/wfblog/p/10549051.html
Copyright © 2011-2022 走看看