<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      實操ES6之Promise

      箭頭函數和this

      寫Promise的時候,自然而然會使用箭頭函數的編寫方式。箭頭函數就是.Neter們熟知的lambda函數,已經被大部分主流語言支持,也受到了廣大碼農的交口稱贊,但是Jser們卻會遇到不大不小的一個坑。

      眾所周知,js函數中的this由調用它的上下文決定,我們還可以通過applycallbind等方式綁定上下文,從而改變函數中this的運行時指向。而當this遇到lambda時,又有所不同。

      function Test() {
          this.name = "alice"
      }
      
      Test.prototype = {
          normal: function () {
              console.info(this.name)
          },
          lambda: () => {
              console.info(this.name)
          }
      }
      
      let test = new Test()
      test.normal() //輸出:alice
      test.lambda() //輸出:undefined
      

      為什么會這樣?網上很多分析,讓人云里霧里。其實只要了解了——lambda與普通方法一個主要區別就是它能保持外層上下文變量的引用——這個特性就明白了。用lambda在方法內寫過嵌套局部方法的.Neter很容易理解這個說法。

              private Action Test()
              {
                  var name = "alice";            
                  Action action = () => Console.WriteLine(name);
                  //name將被捕獲,會一直生存到action被回收
                  return action;
              }
      

      so,可以將js的箭頭函數理解為受運行時外層影響的內嵌函數,它是在運行時賦值的——以上述js代碼為例,js解釋器解釋Test.prototype的定義,解釋到normal函數時,是不care其內部邏輯的,繼續往下解釋到lambda函數時,會過一遍其內部引用到的外部變量,若有則捕獲用于真正執行時(所謂詞法作用域)。此時這個 this 指的是運行環境的根對象(在瀏覽器中可能就是window對象),而不是test對象(此時還不存在噻)。注:本段為個人理解。理解這個概念之后會發現,箭頭函數其實是沒有[屬于自己的] this 的:)

      再看一個代碼片段,請讀者自行嘗試分析下:

      var alice = {
          age: 18,
          getAge: function () {
              var aliceAge = this.age;//this是alice
              var getAgeWithLambda = () => this.age;//this還是alice
              var getAgeWithFunction = function () {
                  return this.age;// this是window
              }
              return[aliceAge,getAgeWithLambda(),getAgeWithFunction()]
          }
      }
      
      console.info(alice.getAge()) //輸出:[18, 18, undefined]
      

      Promise

      Promise主要是將原本的callback變為then,寫出來的代碼更便于閱讀。有多種方式得到一個Promise對象:

      1. Promise.resolve()Promise.resolve('foo') 等價于 new Promise(resolve => resolve('foo'))
      2. 執行async修飾的函數:
      async function newPromise(){}
      let p = newPromise() //p就是Promise對象
      

      如果async函數中是return一個值,這個值就是Promise對象中resolve的值;如果async函數中是throw一個值,這個值就是Promise對象中reject的值。

      1. 直接構造:
      let p = new Promise((resolve, reject)=>{})
      

      注意,構造Promise時內部代碼已經開始執行,只是把resolve部分掛起放到后面執行。測試代碼如下:

      let p = new Promise((resolve, _) => {
          resolve(1);
          console.info(2); //率先執行
      });
      console.info(3);
      p.then(num => {
          console.info(num); //后置執行
      });
      console.info(4);
      
      //輸出:2 3 4 1
      

      所以,這跟慣常認為的整個Promise代碼塊都后置執行不一樣,需要注意。

      我們可以如上述將回調邏輯寫在then里,也可以將邏輯移到外層變為同步執行(而非后置執行),這就需要用到await關鍵字了,它將阻塞當前代碼塊,等待resolve塊執行完再往后執行。代碼如下:

      async function test() {
          let p = new Promise((resolve, _) => {
              resolve(1);
              console.info(2);
          });
          console.info(3);
          let num = await p;
          console.info(num);
          console.info(4);
      }
      
      test()
      
      //輸出:2 3 1 4
      

      ES6引入的Generator函數,是async/await的基礎。

      await讓我們能用同步寫法寫出異步方法,但事實真的如此嗎?在C#領域,這么說尚且沒錯。后端語言大多支持多線程和線程池,await雖然阻塞了后續代碼的執行,但只是上下文被掛起,線程本身是不會被阻塞的還可以干其它事情,await返回后甚至還可以讓其它線程接手,可參看本人以前的博文async、await在ASP.NET[ MVC]中之線程死鎖的故事。js的話,它是單線程,而且它也不像go一樣有完善的協程機制,無法手動(time.sleep()、select{}等)切換代碼塊執行——除非等到await返回,否則線程是沒機會執行其它代碼塊的。 錯誤。
      注意await掛起的不是線程,而是resolve上下文,推測本質上還是與js的執行隊列相關,只不過await后續邏輯都排在resolve之后罷了。

      async function test() {
          let p = new Promise((resolve, _) => {        
              setTimeout(() => {
                  resolve(1)
              }, 5000)
          });
          setTimeout(() => {
              console.info(2)
          }, 3000)
          let num = await p
          console.info(num)
      }
      
      test()
      
      //輸出:2 1
      

      但使用await時仍要注意避免不必要的等待,如果前后幾個Promise沒有依賴關系(更精確的說法是,任務的發起條件不依賴其它任務的結果),那么最好同時發起它們,并在最后await Promise.all(promises)


      異常捕獲

      很多文章都說try/catch在異步模式下無效,其實搭配await的話還是可以的(畢竟await可以使得回調執行在try塊內),如下:

      let testPromise = function () {
          // throw new Error("異步異常測試")
          return Promise.reject(new Error("異步異常測試"))
      }
      
      let testInvocation = async () => {
          try {
              await testPromise()
          } catch (err) {
              console.error(`catch: ${err}`)
          }
      }
      testInvocation() //輸出:catch: Error: 異步異常測試
      

      如果try的是整個testInvocation()那自然沒戲。

      如果覺得在每個異步方法內部try/catch太繁瑣,那么可以抽離出一個模板方法,或者使用process對象注冊uncaughtExceptionunhandledRejection事件,注意這兩者的區別:

      process.on('uncaughtException', e => {
          console.error(`uncaughtException: ${e.message}`)
      }); 
      process.on('unhandledRejection', (reason, promise) => {
          console.error(`unhandledRejection: ${reason}`)
      }); 
      
      let testPromise = function(){
          throw new Error("異步異常測試")
      }
      
      testPromise() //輸出:uncaughtException: 異步異常測試
      
      let testInvocation = async () => await testPromise() //.catch 因為testPromise()返回的不是Promise,所以catch無效
      testInvocation() //輸出:unhandledRejection: Error: 異步異常測試
      
      //注意兩次異常類型不一樣
      

      如果你使用electron開發桌面應用,可能無法[以process.on('unhandledRejection', ...)方式]捕獲unhandledRejection異常(本人使用v10.1.0版本測試發現)。遇到這種情況,只能老老實實在每個Promise后面寫catch()。

      使用process捕獲異常無法獲取異常的上下文,且丟失上下文堆棧使得node不能正常進行內存回收,從而導致內存泄露。
      node中還有個東西domain用于彌補process的問題,但是個人認為domain使用不便,且織入業務代碼程度過深,另外據說目前版本還不穩定(后續可能會更改),甚至有文章說已被node廢棄,具體什么情況暫未深入了解。總之希望node或者js平臺能出一個關于異常捕獲的更好的解決方案。


      協程安全

      在js場景下,異步機制更類似于Go的協程(畢竟js是單線程,多線程無從談起),所以此處取名為協程安全。

      直接看代碼:

      let policy = {}
      
      let testfun = async () => {    
          let data = await policy
          //生成隨機數
          data["key"] = utility.getRandomString(20)
          return data
      }
      
      //1
      let testinfo = async () => {
          let data = await testfun()
          console.info(data.key)    
      }
      
      for (let i = 0; i < 5; i++) {
          testinfo() //注意,每次都是不同的Promise對象
      }
      
      //輸出結果是5次相同的隨機數
      
      //2
      let testinfo2 = async () => {
          for (let i = 0; i < 5; i++) {
              let data = await testfun()
              console.info(data.key)
          }
      }
      
      testinfo2()
      
      //如此則正常輸出5次不同的隨機數
      

      由上可知:在使用await時,若多個await操作相同變量,并且它們的后續操作是在所有await都返回后執行,就容易出現與預期不符的情況,應盡量避免。

      posted @ 2020-09-08 10:51  萊布尼茨  閱讀(752)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 日本中文字幕乱码免费| 亚洲乱码中文字幕小综合| 国产精品久久久久7777| 中文字幕午夜福利片午夜福利片97| 性欧美暴力猛交69hd| 亚洲一区在线成人av| xxxx丰满少妇高潮| 久久精品亚洲中文字幕无码网站| 欧美三级中文字幕在线观看| 伊人久久精品无码麻豆一区| 国产69精品久久久久99尤物| 克什克腾旗| 亚洲春色在线视频| 美女黄18以下禁止观看| 岛国中文字幕一区二区| 弋阳县| 日本三级香港三级人妇99| 久久99精品久久久学生| 开心五月深深爱天天天操| 四川少妇被弄到高潮| 久热这里只有精品12| 午夜激情福利一区二区| 欧美极品色午夜在线视频| 最近中文字幕免费手机版| 亚洲老熟女一区二区三区| 亚洲午夜福利精品无码不卡| 欧美大胆老熟妇乱子伦视频| 汉寿县| 国产欧美日韩高清在线不卡| 2021国产成人精品久久| 天天摸夜夜摸夜夜狠狠添| 伊人久久大香线蕉AV网禁呦| 老色鬼在线精品视频在线观看 | 搡bbbb搡bbb搡| 成人做爰www网站视频| 国产亚洲一二三区精品| 日日碰狠狠添天天爽超碰97| 国产精品女人毛片在线看| 国产在线中文字幕精品| 亚洲国产精品综合久久2007| 精品国产不卡在线观看免费|