欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

await-to-js源碼深入理解處理異步任務(wù)用法示例

 更新時間:2022年08月07日 10:30:35   作者:pino  
這篇文章主要為大家介紹了await-to-js源碼更完美處理異步任務(wù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

如何處理異步任務(wù)?

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

回調(diào)函數(shù)

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

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

例如上面這個例子,fn函數(shù)是一個異步函數(shù),里面執(zhí)行的setTimeout將會在1s之后調(diào)用傳入的callback函數(shù),打印出hello,pino這個結(jié)果。

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

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

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

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)
}

我們想順序?qū)θ齻€函數(shù)的結(jié)果進行順序打印,那么使用傳統(tǒng)的回調(diào)函數(shù)來實現(xiàn)的話,我們可以這樣寫:

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

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

使用回調(diào)函數(shù)的方式來處理異步任務(wù),當回調(diào)函數(shù)過多時,對開發(fā)者的心智負擔是非常重的。

Promise

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

Promise對象是一個構(gòu)造函數(shù),用來生成Promise實例。

Promise構(gòu)造函數(shù)接受一個函數(shù)作為參數(shù),該函數(shù)的兩個參數(shù)分別是resolvereject。

resolve函數(shù): 將Promise對象的狀態(tài)從“未完成”變?yōu)?ldquo;成功”(即從 pending 變?yōu)?resolved),在異步操作成功時調(diào)用,并將異步操作的結(jié)果,作為參數(shù)傳遞出去;

reject函數(shù): 將Promise對象的狀態(tài)從“未完成”變?yōu)?ldquo;失敗”(即從 pending 變?yōu)?rejected),在異步操作失敗時調(diào)用,并將異步操作報出的錯誤,作為參數(shù)傳遞出去。

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

Promise實例生成以后,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調(diào)函數(shù)。

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

then方法可以接受兩個回調(diào)函數(shù)作為參數(shù)。第一個回調(diào)函數(shù)是Promise對象的狀態(tài)變?yōu)?code>resolved時調(diào)用,第二個回調(diào)函數(shù)是Promise對象的狀態(tài)變?yōu)?code>rejected時調(diào)用。其中,第二個函數(shù)是可選的,這兩個函數(shù)都接受Promise對象傳出的值作為參數(shù)。

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

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

可以看到改造完成后的代碼變得非常具有可讀性和條理性。 由于本文的主角不是Promise對象,所以想要深入了解請移步:es6.ruanyifeng.com/#docs/promi…

async

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

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

// 函數(shù)前面加入async關(guān)鍵字
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);
});

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

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

async函數(shù)的出現(xiàn)幾乎將異步函數(shù)完全變?yōu)榱送降膶懛?,使異步任?wù)更容易維護。

Generator

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

一是,function關(guān)鍵字與函數(shù)名之間有一個星號;

二是,函數(shù)體內(nèi)部使用yield表達式,定義不同的內(nèi)部狀態(tài)(yield在英語里的意思就是“產(chǎn)出”)。

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

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

即該函數(shù)有三個狀態(tài):hello,worldreturn 語句(結(jié)束執(zhí)行)。

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

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

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

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

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

上面代碼一共調(diào)用了四次next方法。

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

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

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

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

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

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函數(shù)進行處理:

// 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函數(shù)時,需要手動使用try...catch來進行錯誤捕獲,而await-to-js直接就可以將錯誤返回給用戶。

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

那么await-to-js是如何實現(xiàn)的呢?

源碼解析

其實await-to-js的源碼非常短,只有15行,可以直接看一下源碼中是如何實現(xiàn)的(為了查看源碼更加的直觀,下面的源碼已經(jīng)去除了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函數(shù),他接受兩個參數(shù),promiseerrorExt,其中promise參數(shù)接受一個Promis對象,而errorExt參數(shù)是可選的,先來看一下如果不傳入errorExt參數(shù)是什么樣子的:

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

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

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

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

剛開始看源碼的時候各種不適應(yīng),但是只要沉下心去一步一步的調(diào)試,結(jié)合測試用例,有些東西真的沒有想象中那么難,主要還是重在行動,想到了一個念頭和想法就趕緊去做,拒絕拖沓,只有真正的行動去學習,去獲取,去感知,才能真正的進步!??

最后 ?

未來可能會更新實現(xiàn)mini-vue3javascript基礎(chǔ)知識系列,希望能一直堅持下去,期待多多點贊????,一起進步!

以上就是await-to-js源碼更完美處理異步任務(wù)示例詳解的詳細內(nèi)容,更多關(guān)于await異步任務(wù)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 微信小程序 教程之引用

    微信小程序 教程之引用

    這篇文章主要介紹了微信小程序引用的相關(guān)資料,并附簡單實例代碼,需要的朋友可以參考下
    2016-10-10
  • WebWorker 封裝 JavaScript 沙箱詳情

    WebWorker 封裝 JavaScript 沙箱詳情

    這篇文章主要介紹了WebWorker 封裝 JavaScript 沙箱,在前文 quickjs 封裝 JavaScript 沙箱詳情 已經(jīng)基于 quickjs 實現(xiàn)了一個沙箱,今天這篇文章再基于 web worker 實現(xiàn)備用方案,需要的朋友可以參考一下
    2021-10-10
  • TypeScript中Module使用區(qū)別及模塊路徑解析規(guī)則

    TypeScript中Module使用區(qū)別及模塊路徑解析規(guī)則

    這篇文章主要為大家介紹了TypeScript中Module使用區(qū)別及模塊路徑解析規(guī)則,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • 最新評論