如何將 callback 接口 轉(zhuǎn)化成 Async/Await

背景

今天在使用七牛 nodeJS SDK 做服務(wù)器端文件上傳時(shí),發(fā)現(xiàn)其封裝的API,使用起來非常不方便。于是,想將callback API封裝成自己習(xí)慣的 Async/Await的語法。

問題

我們先看一下七牛代碼

var formUploader = new qiniu.form_up.FormUploader(config);
var putExtra = new qiniu.form_up.PutExtra();
var key='test.txt';
formUploader.put(uploadToken, key, "hello world", putExtra, function(respErr,
  respBody, respInfo) {
  if (respErr) {
    throw respErr;
  }
  if (respInfo.statusCode == 200) {
    console.log(respBody);
  } else {
    console.log(respInfo.statusCode);
    console.log(respBody);
  }
});

formUploader.put方法中,最后一個(gè)參數(shù)是一個(gè)回調(diào)函數(shù),回調(diào)函數(shù)的第一個(gè)參數(shù)是一個(gè) error 參數(shù)。這種風(fēng)格的函數(shù)稱為 Error-First Callback。它有兩個(gè)特征:

  • 回調(diào)的第一個(gè)參數(shù)為一個(gè)錯(cuò)誤對(duì)象
  • 第二個(gè)參數(shù)保留給任何成功的數(shù)據(jù)

在NodeJS的世界中,我們經(jīng)常會(huì)看到這種寫法。但是,這種寫法不是很好維護(hù)。我們需要在回調(diào)中寫很多判斷。除此之外,我們將異步的業(yè)務(wù)邏輯,放入了回調(diào)中。這樣將導(dǎo)致主邏輯不是很清晰。

Node style callbacks (nodebacks) have a particular format where the callbacks is always the last argument and its first parameter is an error.

那么,如何改造這樣的寫法呢?我們想到了 Async/Await,我們都知道異步操作,在編程中是很難處理的。人們?yōu)榱私鉀Q這個(gè)問題,嘗試過callback、promise對(duì)象、Generator函數(shù),但都不夠徹底,使用起來仍不夠簡(jiǎn)潔方便。

異步編程的最高境界,就是根本不用關(guān)心它是不是異步。

解決方法

我們將 formUploader.put方法包一層promise,然后在主邏輯中,調(diào)用它。


const stream_uploader = (token, key, readableStream) => {
  return new Promise((resolve, reject) => {
    formUploader.putStream(token, key, readableStream, putExtra, (res_error, res_body, res_info) => {
      if (res_error) {
        reject(res_error);
      }
    
      if (res_info.statusCode == 200) {
        reslove(res_body);
      } else {
        reject({
          code: res_info.statusCode,
          body: res_body,
        });
      }
    });
  });
}

const main = async () => {
  // ... 獲取token、key業(yè)務(wù)邏輯

  // 將obj,轉(zhuǎn)化為 readableStream 流
  const readableStream = await intoStream(JSON.stringify(obj));

  try {
    const result = await stream_uploader(token, key, readableStream, putExtra);  
  } catch (error) {
    // 處理異常
  }
};

main();

使用 util.promisify Promise化 nodebacks 函數(shù)

const { promisify } = require('util');
const fs = require('fs');

const statAsync = promisify(fs.stat);

statAsync('.').then(stats => {
  console.log(stats);
}).catch((err) => {
  console.log(err);
});

總結(jié)

實(shí)際上,在工作中不用大量手動(dòng)將 nodeback(Error-First Callback) Promise化,可以借助工具實(shí)現(xiàn)這種目的。例如,BluebirdQ、原生的 util.promisify等。

相關(guān)資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容