日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

java 异步得到函数返回值_使用JavaScript进行异步编程

發布時間:2025/3/12 javascript 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 异步得到函数返回值_使用JavaScript进行异步编程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

毫無疑問,雖然JavaScript的歷史比較悠久,但這并不妨礙它成為當今最受歡迎的編程語言之一。對剛接觸該語言的人來說,JavaScript的異步特性可能會有一些挑戰。在本文中,我們將了解和使用Promise和async/await來編寫小型異步程序。通過這些示例,你將了解一些可以在自己程序中使用的異步技巧。

本文中的所有代碼示例都是基于Node環境編寫的,因此建議安裝Node以后運行。雖然所有程序都是為Node編寫的,但類似的語法在瀏覽器中也能同樣運行,它們的異步編程的寫法和原理是通用的。

序言

不管你是否相信JavaScript是一門真正的編程語言,事實是它現在非常的流行。如果你是Web開發人員,你就更應該花一些時間來學習它的優缺點。

JavaScript是單線程的,并且相當于是非阻塞異步流。如果是剛開始使用JavaScript進行異步編程,那么在調試異步代碼時,可能會產生很多煩惱。相比常見的同步編程,異步編程需要更多的耐心和不同的思維方式。

在同步模式中,所有操作都發生在一個隊列(或者中,更易于對程序進行推理;但是在異步模式中,操作可以在任何時間點以任何順序開始或結束,每個函數執行結束的時間是不可預測。因此,僅僅依靠運行的順序序列是不夠的。異步編程需要在程序流程和設計方面進行更多思考。

在本文中,我們會嘗試幾個簡單的異步程序,從簡單到復雜。我們將編寫實現這兩個場景功能:

  • 將文件內容寫入另一個文件。
  • 將多個文件的內容寫入新文件。

Promises 和 async/await

讓我們花點時間快速回顧一下promise和async / await的基礎知識。

Promises

  • Promise是代表異步操作結果的對象。

  • Promise上有兩個回調:resolve(成功之后的回調函數)和reject(失敗后的回調函數)。

  • 一般而言,resolve的結果可以通過then獲取。而reject的結果可以通過catch來獲取。

  • 可以通過new關鍵字來使用Promise構造函數創建Promise。例如:

    const p = new Promise((r, j) => {});

  • 這里r回調在 resolve時調用,j回調在reject時調用。

另外Promise對象有一些實用的靜態方法如all,race,resolve和reject。

  • all方法可以將多個Promise實例包裝成一個新的Promise實例,全部的Promise都resolve的時候返回的是一個結果數組,有任何reject都會使最后的結果變為reject。
  • race就是賽跑的意思,意思就是說,Promise.race([p1, p2, p3])里面哪個結果獲得的快,就返回那個結果,不管結果本身是resolve狀態還是reject狀態。
  • resolve方法創建一個Promise實例并調用resolve方法處理給定參數。
  • reject方法創建一個Promise實例并調用reject方法處理給定參數。

async/await

  • async/await的目的是簡化同時使用多個Promise時的行為,避免了大量使用回調(而帶來的回調地獄)。
  • 正如Promise類似于結構化回調,async/await結合了生成器和 Promise的特點簡化了異步程序的編寫。
  • 可以使用async關鍵字將函數標記為異步函數。即:async function hello() {}或const hello = async() => {};。
  • async函數返回的永遠是一個Promise對象。只要是async函數的返回值,必然會被包含在Promise對象中。
  • 如果async函數內部存在未捕捉到的異常,則通過Promise的reject返回異常。
  • 可以在async函數內部返回Promise對象的語句前使用await 。這種情況下,函數的執行將被“暫停”,直到await的Promise語句執行完畢,并且返回值不再是一個Promise對象而是其resolve的返回結果。
  • await只在async方法內部的有效。

讀寫單個文件

本節中,我們將編寫一個腳本來讀取單個文件的內容,并將其寫入一個新文件。

首先,我們將為程序的入口創建一個async方法:

async

然后,我們需要創建兩個Promise,一個代表文件的內容,另一個代表將內容寫入另一個文件的操作結果:

async

在上面的代碼段中,readFile和writeFile都是異步的,并且都返回一個Promise。因此,需要使用await來確保readFile有返回值,以便在writeFile中使用它:

async

最后,可以考慮一下要在main函數中返回什么。在這里,我們打算返回要寫入的新文件的名稱。要注意的是,返回值將被自動包裝在Promise對象中。但是我們需要使用await來確保在函數執行完之前得到了writeFile的結果:

async

現在,我們可以調用main函數并將結果或任何未捕獲的異常打印出來:

main()
.then(r => console.log("Result:", r))
.catch(err => console.log("An error occurred", err);

為了使程序更加完整,我們需要使用fs模塊并將fs.readFile和fs.writeFilePromise化,即promisify。完整的腳本如下所示:

const util =

在上面的代碼段中,我們Promise化了fs.writeFile和fs.readFile。promisify函數可以將任何遵循Node.js回調風格的函數,轉換為基于Promise的函數。

接下來我們聊聊異常處理。你可以通過好幾種方法來處理異常,具體取決于你想處理到什么程度。例如,在上面的代碼片段中,我們在catch塊里基本上捕獲了main函數中可能發生的任何異常。不過它只在async方法內有用,未捕獲的異常會通過該函數的reject返回。

但是,假設你想做更多的控制,并且希望根據每個async方法的錯誤來做不同的操作。在這種情況下,你可以在每個異步操作中使用try-catch或catch。

使用try-catch的情況

我們先來看一下用try-catch的情況。

async

在上面的代碼段中,我們添加了兩個try-catch塊。另外,我們在第一個程序塊try-catch之外創建了fileContent變量,以便在整個main函數中可用。注意,在每個try-catch中,如果出現異常,我們返回的是一個對象。錯誤對象包含一個消息字段和錯誤的詳細信息。如果發生任何錯誤,函數會立即返回我們自定義的錯誤對象。請記住,返回的對象會被自動包含在Promise中。我們可以像以前一樣調用main函數,不過這次可以在then()中檢查錯誤對象:

main()
.then(r => {
if(r.error) {
return console.log(
"An error occurred, recover here. Details:", r);
}
return console.log("Done, no error. Result:", r);
})
.catch(err => console.log("An error occurred", err));

注意,在then()中,我們會檢查resolve對象是否存在錯誤。如果有,那么我們在這里進行錯誤處理;否則,我們只需將結果打印到日志。另一個catch塊將捕獲運行時錯誤或程序未處理的其他錯誤。

使用catch的情況

除了try-catch,我們也可以通過給每個Promise綁定一個catch來處理異常:

async

這里你可能注意到了,我們給每個Promise?都加了catch方法,并返回一個自定義錯誤對象,類似于前面的示例。如果其中一個步驟有錯誤,將只返回這一步的結果,該結果僅包含我們的自定義錯誤對象。

但是,對于第二個操作,如果寫操作成功,我們將明確地返回一個空對象。這是因為writeFile操作成功時傳遞給resolve的是undefined,而我們無法訪問undefined值的error字段。所以如果寫入成功,我們要返回一個resolve空對象的Promise。

我們還可以寫兩個輔助函數,減少一些重復代碼:

const call =

call函數接受一個Promise,并返回一個Promise。如果結果為null或未定義,Promise將使用空對象進行處理;或者是操作的結果。如果有錯誤,將解析為一個包含錯誤信息的error對象。

error輔助函數需要result和msg兩個參數,它將返回包含錯誤結果和自定義消息的對象。

添加這兩個函數后,我們可以更新main函數:

async

這里,我們將每個操作傳遞給call函數。然后檢查是否有錯誤,如果有,那么只需調用error函數以返回帶有自定義錯誤消息的自定義錯誤。完整的代碼如下所示:

const util =

為了更多地減少重復代碼并使它變得更加模塊化,我們還可以做兩件事:

  • 使用fs-extra并刪除所有對util.promisify的調用。
  • 將這兩個輔助函數放到它們自己的文件中。

之后,我們將得到以下內容:

const fs =

注意,由于我們正在使用fs-extra,如果不將回調傳遞給方法,則該函數默認將返回一個Promise。這就是為什么我們刪除所有promisify調用,并直接在fs變量上轉換所有fs調用的原因。另外,我們將兩個輔助函數放到了他們自己的call.js文件中。

讀寫多個文件

在本節中,我們將編寫一個腳本,該腳本讀取多個文件的內容并將結果寫入新文件。此示例的設置與上一節非常相似:

const fs =

在上面的代碼段中,首先我們需要fs-extra具有所有基于Promise的方法版本的模塊fs。然后,我們將main async函數定義為程序的入口點。我們還定義了一個數組,其中包含要讀取的文件的硬編碼路徑。

接下來,我們將編寫一個遍歷文件路徑的for循環,并讀取每個文件的內容:

const fs =

在A行上,我們定義了for循環。在B行await上,我們根據的結果,fs.readFile并將其分配給content變量。最后,在C行中,我們將內容記錄到控制臺。讓我們用實際的寫文件操作替換log語句:

const fs =

在上面的代碼段中,我們首先在A行中定義文件的路徑。然后在B行中,將結果寫入新路徑,并確保await在其上也是如此。我們需要在await這里,因為我們要確保在移至下一個文件之前完成寫入。最后在C行,我們返回輸入文件路徑。

現在,上面的實現還可以,但是我們可以做得更好。在上面的實現中,我們一次處理一個文件。也就是說,我們等待每個文件的讀寫操作完成,然后再移動到下一個文件。實際上,我們可以通過創建一個Promise數組并發地運行每個讀寫過程,其中的每個Promise表示對文件的讀寫操作。最后,我們可以用來Promise.all(Promise[])方法同時處理所有Promise:

const fs =

在上面的代碼段中,我們在A行上定義了一個數組來保存讀寫Promise。在行B上,我們開始遍歷每個文件路徑的for循環。在C行上,我們將自調用async函數推入readWrites數組。在每個async函數的主體內,我們讀取每個文件的內容并寫入一個新文件。在F行上,我們返回的結果fs.writeFile是一個Promise對象。最后,在G行中,我們用于Promise.all同時處理所有Promise。我們還await對結果進行解析,該結果解析為保存寫入結果的單個數組。如果寫操作成功,我們應該得到一個未定義值的數組。這是因為write方法解析為undefined沒有發生錯誤。

即使上面的實現完成了工作,我們也可以做得更好。我們可以在files數組上使用帶有async函數的map方法,而無需使用自調用async函數。它也將更容易理解:

const fs =

在上面的代碼的A行中我們對files數組執行map方法,把它傳遞給一個async函數。在async函數內部,我們僅執行讀寫操作。最后在D行,我們調用Promise.all并傳遞readWrites數組。該readWrites數組保存了多個Promise,其中每個Promise代表每次讀取和寫入的結果。

現在,讓我們擴展上面的示例。讓我們創建一個文件夾,并將所有新文件放入其中。async在進行讀寫操作之前,我們將需要創建一個函數來為我們創建輸出文件夾:

async

在上面的代碼段中,我們首先創建一個async名為的函數prepare。在A行,首先,output如果文件夾已經存在,則將其刪除。我們還等待Promise完成,然后再移至B行。在B行上,我們創建了output文件夾,我們也等待完成。現在,在開始讀寫操作之前,我們可以在prepare函數內部使用該函數main:

const fs =

在A行上,我們等待prepare函數完成,然后再進行讀寫操作。我們還在行B上更新了輸出文件路徑。腳本的其余部分幾乎相同。我們還將filesand?output變量移到了main函數之外。如果運行上面的腳本,應該會看到一個output包含每個輸入文件副本的文件夾。

結論

JavaScript從誕生到現在,已經演化為一個非常先進易用的語言,并且Promise以及async/await使異步程序變得更易寫也更易讀。現在我們已經到了文章的結尾,讓我們回顧一些其它的要點:

  • 我們可以Promise.all與數組的map方法一起使用來創建Promise并同時處理它們。我們也可以在Promise.all等待所有Promise被完成之前使用await運算符,即:await Promise.all(inputs.map(async v => {}));
  • 如果要在async函數內部使用try-catch塊,則需要在返回Promise的任何Promise值或函數之前使用await運算符。

JavaScript是一個功能強大的全棧語言,不僅可以開發Web前端,也使用Node.js開發后端,使用Electron開發桌面應用。同時也可以結合CukeTest、LeanRunner等工具開發自動化測試及RPA,應了那句老話"學好JavaScript,走遍天下都不怕"。學好異步編程是掌握JavaScript的關鍵,希望這篇文章對你有所幫助。

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的java 异步得到函数返回值_使用JavaScript进行异步编程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。