首頁 web前端 js教程 javascript中async的用法詳解

javascript中async的用法詳解

Aug 23, 2017 pm 02:00 PM
async javascript js

這篇文章主要介紹了理解javascript async的用法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟著小編過來看看吧

寫在前面

#本文將會實作一個順序讀取檔案的最優方法,實作方式從最古老的回呼方式到目前的async,也會與大家分享下本人對於thunk函式庫與co函式庫的理解。實現的效果:順序讀取出a.txt與b.txt,將讀出的內容拼接成為一個字串。

同步讀取


const readTwoFile = () => {
  const f1 = fs.readFileSync('./a.txt'),
    f2 = fs.readFileSync('./b.txt');
  return Buffer.concat([f1, f2]).toString();
};
登入後複製

這種方式最利於我們理解,程式碼也很清楚,沒有太多的嵌套,很好的維護,但是這種有著最大的問題,那就是性能,node所倡導的就是異步i/o來處理密集i/o,而同步的讀取,很大的程度上浪費著伺服器的cpu,這種方式的弊端明顯的大於好處,所以直接pass掉。 (其實node的任何非同步程式設計的解決方案的目標都是要達到同步的語義,非同步的執行。)

##利用回呼讀取




const readTwoFile = () => {
  let str = null;
  fs.readFile('./a.txt', (err, data) => {
    if (err) throw new Error(err);
    str = data;
    fs.readFile('./b.txt', (err, data) => {
      if (err) throw new Error(err);
      str = Buffer.concat([str, data]).toString();
    });
  });
};
登入後複製

利用回呼的方式,實現起來很簡單,直接的嵌套下去就好,但是這種情況下很容易造成的就是不易維護,難以讀懂的情況,最為極致的情況的就是回調地獄。

Promise實作

  • const readFile = file => 
      new Promise((reslove, reject) => {
        fs.readFile(file, (err, data) => {
          if (err) reject(err);
          reslove(data);
        });
      });
    const readTwoFile = () => {
      let bf = null;
      readFile('./a.txt')
        .then(
          data => {
            bf = data;
            return readFile('./b.txt');
          }, 
          err => { throw new Error(err) }
        )
        .then(
          data => {
            console.log(Buffer.concat([bf, data]).toString())
          }, 
          err => { throw new Error(err) }
        );
    };
    登入後複製

    Promise可以將橫向成長的回呼轉換為縱向成長,能解決一些問題,但Promise造成的問題就是程式碼冗餘,一眼看過去,全部是then,也不是很爽,但是相比於回呼函數嵌套來說,已經有了很大的提升。

  • yield

  • Generator很多語言都有,本質上是協程,下面就來看協程,線程,進程的區別與聯繫:

進程:作業系統中分配資源的基本單位


#執行緒:作業系統中調度資源的基本單位


#協程:比執行緒更小的執行單元,自帶cpu上下文,一個協程一個堆疊


一個行程中可能存在多個執行緒,一個執行緒中可能存在多個協程,行程、執行緒的切換由作業系統控制,而協程的切換由程式設計師本身控制。非同步i/o利用回呼的方式來應對i/o密集,同樣的使用協程也可以來應對,協程的切換並沒有很大的資源浪費,將一個i/o操作寫成一個協程,這樣進行i/o時可以吧cpu讓給其他協程。


js同樣支援協程,那就是yield。使用yield給我們直覺的感受就是,執行到了這個地方停了下來,其他的程式碼繼續跑,到你想讓他繼續執行了,他就是會繼續執行。

function *readTwoFile() {
  const f1 = yield readFile('./a.txt');
  const f2 = yield readFile('./b.txt'); 
  return Buffer.concat([f1, f2]).toString();
}
登入後複製

yield下的順序讀取呈現的也是一種順序讀取的方式,對於readFile來看有兩種不同的實作方式,

利用thunkify


const thunkify = (fn, ctx) => (...items) => (done) => {
  ctx = ctx || null;
  let called = false;
  items.push((...args) => {
    if (called) return void 0;
    called = true;
    done.apply(ctx, args);
  });
  try {
    fn.apply(ctx, items);  
  } catch(err) {
    done(err);
  }
};
登入後複製

thunkify函數就是一種柯里化得思想,最後的傳入參數done就為回呼函數,利用thunkify可以很輕鬆的實作yield函數的自動化流程:


const run = fn => {
  const gen = fn();
  let res;
  (function next(err, data) {
    let g = gen.next(data);
    if (g.done) return void 0;
    g.value(next);
  })();
};
登入後複製

利用Promise


const readFile = file => 
  new Promise((reslove, reject) => {
    fs.readFile(file, (err, data) => {
      if (err) reject(err);
      reslove(data);
    });
  });
const run = fn => {
  const gen = fn();
  let str = null;
  (function next(err, data) {
    let res = gen.next(data);
    if (res.done) return void 0;
    res.value.then(
      data => {
        next(null, data);
      }, 
      err => { throw new Error(err); }
    );
  })();
};
run(readTwoFile);
登入後複製

上面兩種方式都可以達到自動執行yield的過程,那麼有沒有一種方式,可以兼容這兩種實現方式呢,tj大神又給了一個庫,那就是co庫,先來看下用法:


// readTwoFile的实现与上面类似,readFile既可以利用Promise也可以利用thunkify
// co库返回一个Promise对象
co(readTwoFile).then(data => console.log(data));
登入後複製

來看下co庫的實現,co庫預設會傳回一個Promise對象,對於yield之後的值(如上面的res.value),co庫會將其轉換為一個Promise。實作思想很簡單,基本上還是利用遞歸的方式,大體的想法如下:


const baseHandle = handle => res => {
  let ret;
  try {
    ret = gen[handle](res);
  } catch(e) {
    reject(e);
  }
  next(ret);
};
function co(gen) {
  const ctx = this,
    args = Array.prototype.slice.call(arguments, 1);
  return new Promise((reslove, reject) => {
    if (typeof gen === 'function') gen = gen.apply(ctx, args);
    if (!gen || typeof gen.next !== 'function') return resolve(gen);

    const onFulfilled = baseHandle('next'),
      onRejected = baseHandle('throw');

    onFulfilled();

    function next(ret) {
      if (ret.done) reslove(ret.value);
      // 将yield的返回值转换为Proimse
      const value = toPromise.call(ctx, ret.value);
      if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
      return onRejected(new TypeError('yield type error'));
    }
  });
}
登入後複製

toPromise就是將一些型別轉換為Promise,從這裡我們可以看出的是可以將哪些型別放在yield後面,這裡就來看一個常用的:


// 把thunkify之后的函数转化为Promise的形式
function thunkToPromise(fn) {
  const ctx = this;
  return new Promise(function (resolve, reject) {
    fn.call(ctx, function (err, res) {
      if (err) return reject(err);
      if (arguments.length > 2) res = slice.call(arguments, 1);
      resolve(res);
    });
  });
}
登入後複製

最近Node已經支援了async/await,可以利用其來做非同步操作:

######終極解決##################
const readFile = file => 
  new Promise((reslove, reject) => {
    fs.readFile(file, (err, data) => {
      if (err) reject(err);
      reslove(data);
    });
  });
const readTwoFile = async function() {
  const f1 = await readFile('./a.txt');
  const f2 = await readFile('./b.txt');  
  return Buffer.concat([f1, f2]).toString();
};
readTwoFile().then(data => {
  console.log(data);
});
登入後複製
###async/await做的就是將Promise物件給串聯起來,避免了then的呼叫方式,程式碼非常的易讀,就是一種同步的方式。不再需要藉助其他外界類別庫(例如co庫)就可以優雅的解決回呼的問題######

以上是javascript中async的用法詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

建議:優秀JS開源人臉偵測辨識項目 建議:優秀JS開源人臉偵測辨識項目 Apr 03, 2024 am 11:55 AM

人臉偵測辨識技術已經是一個比較成熟且應用廣泛的技術。而目前最廣泛的網路應用語言非JS莫屬,在Web前端實現人臉偵測辨識相比後端的人臉辨識有優勢也有弱勢。優點包括減少網路互動、即時識別,大大縮短了使用者等待時間,提高了使用者體驗;弱勢是:受到模型大小限制,其中準確率也有限。如何在web端使用js實現人臉偵測呢?為了實現Web端人臉識別,需要熟悉相關的程式語言和技術,如JavaScript、HTML、CSS、WebRTC等。同時也需要掌握相關的電腦視覺和人工智慧技術。值得注意的是,由於Web端的計

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

股票分析必備工具:學習PHP和JS繪製蠟燭圖的步驟 股票分析必備工具:學習PHP和JS繪製蠟燭圖的步驟 Dec 17, 2023 pm 06:55 PM

股票分析必備工具:學習PHP和JS繪製蠟燭圖的步驟,需要具體程式碼範例隨著網路和科技的快速發展,股票交易已成為許多投資者的重要途徑之一。而股票分析是投資人決策的重要一環,其中蠟燭圖被廣泛應用於技術分析。學習如何使用PHP和JS繪製蠟燭圖將為投資者提供更多直觀的信息,幫助他們更好地做出決策。蠟燭圖是一種以蠟燭形狀來展示股票價格的技術圖表。它展示了股票價格的

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

PHP與JS開發技巧:掌握繪製股票蠟燭圖的方法 PHP與JS開發技巧:掌握繪製股票蠟燭圖的方法 Dec 18, 2023 pm 03:39 PM

隨著網路金融的快速發展,股票投資已經成為了越來越多人的選擇。而在股票交易中,蠟燭圖是常用的技術分析方法,它能夠顯示股票價格的變動趨勢,幫助投資人做出更精準的決策。本文將透過介紹PHP和JS的開發技巧,帶領讀者了解如何繪製股票蠟燭圖,並提供具體的程式碼範例。一、了解股票蠟燭圖在介紹如何繪製股票蠟燭圖之前,我們首先需要先了解什麼是蠟燭圖。蠟燭圖是由日本人

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

See all articles