91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么使用await-to-js源碼處理異步任務

發布時間:2022-08-08 14:16:10 來源:億速云 閱讀:137 作者:iii 欄目:開發技術

本篇內容介紹了“怎么使用await-to-js源碼處理異步任務”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

    如何處理異步任務?

    我們先從一個老生常談的問題開始。

    回調函數

    由于javascript是一門單線程的語言,所以我們早期來處理異步場景的時候,大部分是通過回調函數來進行處理的。

    var fn = function(callback){
        setTimeout(function(){
            callback()
        },1000)
    }
    fn(function(){console.log('hello, pino')})

    例如上面這個例子,fn函數是一個異步函數,里面執行的setTimeout將會在1s之后調用傳入的callback函數,打印出hello,pino這個結果。

    但是當我們有多個異步操作的時候,就需要有多個異步函數進行嵌套,代碼將會變得更加臃腫和難以維護。

    setTimeout(function(){
        console.log('執行了')
        setTimeout(function(){
            console.log('再次執行了')
            //.....
        },2000)
    },1000)

    同樣的,還有一個例子: 假設我們有fn1,fn2,fn3三個異步函數:

    let fn1 = function(){
        setTimeout(function(){
            console.log('pino')
        },1000)
    }
    let fn2 = function(){
        setTimeout(function(){
            console.log('愛吃')
        },3000)
    }
    let fn3 = function(){
        setTimeout(function(){
            console.log('瓜')
        },2000)
    }

    我們想順序對三個函數的結果進行順序打印,那么使用傳統的回調函數來實現的話,我們可以這樣寫:

    var makefn = function(text,callback,timer){
        setTimeout(function(){
            console.log(text)
            callback()
        },timer)
    }
    makefn('pino',function(){
        makefn('愛吃',function(){
            makefn('瓜',function(){
                console.log('結束了~')
            },2000)
        },3000)
    },1000)

    可以看到當回調任務過多的時候,我們的代碼將會變的非常臃腫,尤其是多個異步函數之間層層嵌套,這就形成了回調地獄。

    使用回調函數的方式來處理異步任務,當回調函數過多時,對開發者的心智負擔是非常重的。

    Promise

    promise對象的出現其實是對js處理異步任務邁出的一大步,它提供了非常多的針對異步的處理方法,錯誤捕獲鏈式調用...

    Promise對象是一個構造函數,用來生成Promise實例。

    Promise構造函數接受一個函數作為參數,該函數的兩個參數分別是resolvereject

    resolve函數: 將Promise對象的狀態從“未完成”變為“成功”(即從 pending 變為 resolved),在異步操作成功時調用,并將異步操作的結果,作為參數傳遞出去;

    reject函數: 將Promise對象的狀態從“未完成”變為“失敗”(即從 pending 變為 rejected),在異步操作失敗時調用,并將異步操作報出的錯誤,作為參數傳遞出去。

    const person = new Promise((resolve,reject) => {
        let num = 6;
        if(num>5){
            resolve()
        }else{
            reject()
        }
    })

    Promise實例生成以后,可以用then方法分別指定resolved狀態和rejected狀態的回調函數。

    promise.then(function(value) {
      // success
    }, function(error) {
      // failure
    });

    then方法可以接受兩個回調函數作為參數。第一個回調函數是Promise對象的狀態變為resolved時調用,第二個回調函數是Promise對象的狀態變為rejected時調用。其中,第二個函數是可選的,這兩個函數都接受Promise對象傳出的值作為參數。

    例如我們將上面的順序打印三個異步函數進行改造:

    makefn('pino',function(){
        makefn('愛吃',function(){
            makefn('瓜',function(){
                console.log('結束了~')
            },2000)
        },3000)
    },1000)
    //改造后
    fn('pino',1000).then(function(){
        return fn('愛吃',3000)
    })
    .then(function(){
        return fn('瓜',2000)
    })
    .then(function(){
        console.log('結束了~')
    })

    可以看到改造完成后的代碼變得非常具有可讀性和條理性。

    async

    ES2017 標準引入了 async 函數,使得異步操作變得更加方便。

    async函數返回一個 Promise 對象,可以使用then方法添加回調函數。當函數執行的時候,一旦遇到await就會先返回,等到異步操作完成,再接著執行函數體內后面的語句。

    // 函數前面加入async關鍵字
    async function getAllData(name) {
      // 遇到await會暫停,并返回值
      const data = await getData(name);
      const options = await getSelect(name);
      return options;
    }
    getAllData('pino').then(function (result) {
      console.log(result);
    });

    下面繼續使用async的方式來改造一下文章開頭的例子:

    async function makeFn() {
      let fn1 = await fn1()
      let fn2 = await fn2()
      let fn3 = await fn3()
    }

    async函數的出現幾乎將異步函數完全變為了同步的寫法,使異步任務更容易維護。

    Generator

    形式上, Generator 函數是一個普通函數,但是有兩個特征。

    一是,function關鍵字與函數名之間有一個星號;

    二是,函數體內部使用yield表達式,定義不同的內部狀態(yield在英語里的意思就是“產出”)。

    function* helloWorldGenerator() {
      yield 'hello';
      yield 'world';
      return 'ending';
    }
    var p1 = helloWorldGenerator();

    上面代碼定義了一個 Generator 函數helloWorldGenerator,它內部有兩個yield表達式(hello和world

    即該函數有三個狀態:hello,worldreturn 語句(結束執行)。

    然后, Generator 函數的調用方法與普通函數一樣,也是在函數名后面加上一對圓括號。

    不同的是,調用 Generator 函數后,該函數并不執行,返回的也不是函數運行結果,而是一個指向內部狀態的指針對象,也就是上一章介紹的遍歷器對象(Iterator Object)。 下一步,必須調用遍歷器對象的next方法,使得指針移向下一個狀態。

    也就是說,每次調用next方法,內部指針就從函數頭部或上一次停下來的地方開始執行,直到遇到下一個yield表達式(或return語句)為止。

    換言之, Generator 函數是分段執行的,yield表達式是暫停執行的標記,而next方法可以恢復執行。

    p1.next()
    // { value: 'hello', done: false }
    p1.next()
    // { value: 'world', done: false }
    p1.next()
    // { value: 'ending', done: true }
    p1.next()
    // { value: undefined, done: true }

    上面代碼一共調用了四次next方法。

    Generator 函數也可以進行異步任務的處理,上面的async函數就是Generator 函數的語法糖,而兩者之間最大的區別就是async函數內置了自執行器,也就是說無需手動調用next()方法,async函數就會幫我們繼續向下執行,而Generator 函數不會自動調用next()方法,只能進行手動調用,下面實現一個簡易執行器:

    // 接受一個Generator函數
    function run(gen){
      var g = gen();
      function next(data){
        var result = g.next(data);
        if (result.done) return result.value;
        // 只要返回的dong不為true,沒有執行完畢,就繼續調用next函數,繼續執行
        result.value.then(function(data){
          next(data);
        });
      }
      next();
    }
    run(gen);

    使用Generator 函數來該寫一下之前的案例,其實只需要將await更換為yield

    function* makeFn() {
      let fn1 = yield fn1()
      let fn2 = yield fn2()
      let fn3 = yield fn3()
    }

    本文只是簡略的講解了Generator 函數和async函數,如果像深入學習,請移步:

    es6.ruanyifeng.com/#docs/async

    es6.ruanyifeng.com/#docs/gener…

    什么是await-to-js?

    說了這么多,今天的主角await-to-js到底是干啥的?解決了什么問題?

    先來看一下作者的定義:

    Async await wrapper for easy error handling without try-catch。

    異步等待封裝器,便于錯誤處理,不需要try-catch

    先來看一下如何使用:

    安裝

    npm i await-to-js --save

    對比一下使用await-to-js后,我們在代碼中處理錯誤捕獲有什么不同,這里使用async函數進行處理:

    // async的處理方式
    function async getData() {
        try {
          const data1 = await fn1()
        } catch(error) {
          return new Error(error)
        }
        try {
          const data2 = await fn2()
        } catch(error) {
          return new Error(error)
        }
        try {
          const data3 = await fn3()
        } catch(error) {
          return new Error(error)
        }
    }
    // 使用await-to-js后
    import to from './to.js';
    function async getData() {
       const [err, data1]  = await to(promise)
       if(err) throw new (error);
       const [err, data2]  = await to(promise)
       if(err) throw new (error);
       const [err, data3]  = await to(promise)
       if(err) throw new (error);
    }

    可以看到,使用await-to-js后我們的代碼變得精簡了許多,在使用async函數時,需要手動使用try...catch來進行錯誤捕獲,而await-to-js直接就可以將錯誤返回給用戶。

    所以根據上面的例子,可以得出結論,await-to-js的作用就是封裝了錯誤捕獲的處理函數,使異步的操作更加的方便。

    那么await-to-js是如何實現的呢?

    源碼解析

    其實await-to-js的源碼非常短,只有15行,可以直接看一下源碼中是如何實現的(為了查看源碼更加的直觀,下面的源碼已經去除了typescript語法):

    export function to(
      promise,
      errorExt
    ){
      return promise
        .then((data) => [null, data])
        .catch((err) => {
          if (errorExt) {
            const parsedError = Object.assign({}, err, errorExt);
            return [parsedError, undefined];
          }
          return [err, undefined];
        });
    }

    可以看到await-to-js中直接返回了to函數,他接受兩個參數,promiseerrorExt,其中promise參數接受一個Promis對象,而errorExt參數是可選的,先來看一下如果不傳入errorExt參數是什么樣子的:

    export function to(promise, errorExt){
      // 使用then和catch來執行和捕獲錯誤
      return promise
        .then((data) => [null, data])
        .catch((err) => {
          return [err, undefined];
        });
    }

    to函數直接返回了傳入的Promise對象,并定義了then函數和catch函數,無論成功還是失敗都返回一個數組,數組的第一項是錯誤結果,如果執行成功則返回null,執行失敗則返回錯誤信息,數組的第二項為執行結果,執行成功則返回響應成功的結果,如果執行失敗則返回undefined,這也是非常符合預期的。

    那么第二個參數是干什么的呢?第二個參數errorExt是可選的,他接收一個對象,主要用于接收用戶自定義的錯誤信息,然后使用Object.assign將自定義信息與錯誤信息合并到一個對象,返回給用戶。

    .catch((err) => {
      if (errorExt) {
        // 合并錯誤對象:默認錯誤信息+用戶自定義錯誤信息
        const parsedError = Object.assign({}, err, errorExt);
        // 返回錯誤結果
        return [parsedError, undefined];
      }
    });

    “怎么使用await-to-js源碼處理異步任務”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    库尔勒市| 洱源县| 惠来县| 临澧县| 镇坪县| 阿克陶县| 阿城市| 普陀区| 喀喇沁旗| 阿巴嘎旗| 隆林| 汕头市| 太康县| 繁峙县| 南木林县| 施秉县| 灯塔市| 道真| 磐石市| 绥滨县| 六枝特区| 汪清县| 玉林市| 万盛区| 西贡区| 禹州市| 汉源县| 民乐县| 扶风县| 金川县| 宣威市| 嘉义市| 仁怀市| 萝北县| 安陆市| 南丰县| 凤台县| 中超| 渝中区| 蒙山县| 微博|