更優雅的方式: JavaScript 中順序執行非同步函數

来源:https://www.cnblogs.com/givebest/archive/2018/04/05/8721371.html
-Advertisement-
Play Games

火於非同步 1995年,當時最流行的瀏覽器——網景中開始運行 JavaScript (最初稱為 LiveScript)。 1996年,微軟發佈了 JScript 相容 JavaScript。隨著網景、微軟競爭而不斷的技術更新,在 2000年前後,JavaScript 相關的技術基礎準備就緒。 隨後到 ...


火於非同步

1995年,當時最流行的瀏覽器——網景中開始運行 JavaScript (最初稱為 LiveScript)。 1996年,微軟發佈了 JScript 相容 JavaScript。隨著網景、微軟競爭而不斷的技術更新,在 2000年前後,JavaScript 相關的技術基礎準備就緒。 隨後到 2005 年前後,以 Google 為首開始重視使用 AJAX(即 Asynchronous JavaScript and XML),使得複雜的網頁交互體驗接近桌面應用。

然後,隨著 Web 應用變得越來越複雜 ,JavaScript 的生態和重要性也日益提升,YUI、prototype.js、jQuery 等各種庫相應登場,隨之而來就到了 JavaScript 的繁榮期。

2008年,Google 發佈了 JavaScript 引擎 V8 大大改善了 JavaScript 的執行速度,進一步推動了 JavaScript 的繁榮,也為 JavaScript 進軍伺服器端打下了基礎(如:Node.js)。

順序執行非同步函數

非同步為 JavaScript 帶來非阻塞等優勢的同時,同時也在一些場景下帶了不便,如:順序執行非同步函數,下麵總結了一些常用的方法。

1. "回調地獄"

隨著應用複雜度幾何式增加,我們可能遇到下麵“回調地獄”式的代碼。

// 第一個任務
function task1 (callback) {
  setTimeout(() => {
    console.log('1', '我是第一個任務,必須第一個執行');
    callback && callback(1);
  }, 3000);
}

// 第二個任務
function task2 (callback) {
  setTimeout(() => {
    console.log('2', '我是第二個任務');
    callback && callback(2);
  }, 1000);
}

// 第三個任務
function task3 (callback) {
  setTimeout(() => {
    console.log('3', '我是第三個任務');
    callback && callback(3);
  }, 1000);
}

// 所有任務
function allTasks () {
  task1((cb1) => {
    if (cb1) {
      task2((cb2) => {
        if (cb2) {
          task3((cb3) => {
            if (cb3) {
              // 順序完成所有任務
            }
          })
        }   
      });
    }
  });
}

allTasks();

/**
 * 3秒後
 * 1 我是第一個任務,必須第一個執行
 * 1秒後
 * 2 第二個任務
 * 1秒後
 * 3 第三個任務
 */

2. Promise

為了避免“回調地獄”帶來的複雜性和不易閱讀,ES6 推出了 Promise。這次實現起來簡單多了,但還存在 Promise 中嵌套多層 Promise 的問題,似乎又回到了類似“回調地獄”的問題上。

new Promise(resolve => {
  setTimeout(() => {
    console.log('1', '我是第一個任務,必須第一個執行');
    resolve(1);
  }, 3000);
}).then((val) => {

  new Promise(resolve => {
    setTimeout(() => {
      console.log('2', '我是第二個任務');
      resolve(2);
    }, 1000);
  }).then(val => {
    setTimeout(() => {
      console.log('3', '我是第三個任務');
    }, 1000); 
  });

});
/**
 * 3秒後
 * 1 我是第一個任務,必須第一個執行
 * 1秒後
 * 2 第二個任務
 * 1秒後
 * 3 第三個任務
 */

3. Await、Async

確保支持,詳細見:https://caniuse.com/#search=async

為了更易書寫和閱讀來實現順序執行非同步函數,ES2017 新增了 awaitasync。這次書寫體驗非常的棒,就像寫同步代碼一樣完成了順序執行非同步的需求。

/**
 * 第一個任務
 */
function task1 () {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('1', '我是第一個任務,必須第一個執行');
      resolve('done');
    }, 3000);
  });
}

/**
 * 第二個任務
 */
function task2 () {

  return new Promise(resolve => {
    setTimeout(() => {
      console.log('2', '第二個任務');
      resolve('done');
    }, 1000)
  });
}

/**
 * 第三個任務
 */
function task3 () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('3', '第三個任務');
      reject('error');
    }, 1000);
  });
}

/**
 * 第四個任務
 */
function task4 () {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('4', '第四個任務');
      resolve('done');
    }, 2000);
  })
}

/**
 * 所有任務
 */
async function allTasks () {
  await task1();
  await task2();
  await task3();
  await task4();
}

// 執行任務
allTasks();

/**
 * 3秒後
 * 1 我是第一個任務,必須第一個執行
 * 1秒後
 * 2 第二個任務
 * 1秒後
 * 3 第三個任務
 * Uncaught (in promise) error
 */
完整案例

基於 Node.js,通過 Await 、Async、Promise 實現的順序執行非同步,爬取豆瓣電影截圖並按順序一張張下載圖片。

參考

轉載請註明出處: http://blog.givebest.cn/javascript/2018/04/05/javascript-sync.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 今天特意花白天的時間來寫畢設,終於把老師的第二次課結束了,還剩四次課。 昨天的bug說一下吧,居然是寫錯了一個方法對象,漏寫了個 ' r ' ,結果導致整個頁面都渲染不出來…… 寫代碼果然還是需要更多的耐心和細心才行。 其實昨天,老師還用到了一個parserbody中間件,是一個HTTP請求解析中間 ...
  • 寫作用域插槽之前,先介紹一下Vue中的slot內容分發: 如果<child-component></child-component>標簽之間沒有插入那兩個p標簽的話,頁面會顯示子組件模板中定義的“<p>父組件如果沒有插入內容,我將被顯示</p>”這一則內容,但如果<child-component>< ...
  • 由於某些不可描述的原因,俺的某個小項目要用客戶端桌面應用,後臺那還是 php 了。經廣大的群友指導,發現了 Electron 這個項目。它可以用 html, css, javascript 構建跨平臺的桌面應用程式,基於 nodejs 實現。 然而在安裝 Electron 時,卡死在了 npm in ...
  • 開發環境搭建完成。二、編譯部署1、項目路徑下demo輸入命令npm run build編譯完成後會發現在demo文件夾下多出一個dist文件夾這裡面就是編譯好的文件了。2、網上下載nginx,下載地址http://nginx.org/en/download.html,解壓下載的nginx文件。3、配 ...
  • 在Angular中,組件屬於特殊的指令,它的特殊之處在於它有自己的模板(html)和樣式(css)。因此使用組件可以使我們的代碼具有強解耦、可復用、易擴展等特性。通常的組件定義如下: demo.component.ts: demo.component.html: demo.component.scs ...
  • text() 方法方法設置或返回被選元素的文本內容(innerText): html() 方法返回或設置被選元素的內容 (innerHTML),包括標簽: <input type="text" id="input" value="1133445fddsgfsgfadfa"> val() 方法返回或設 ...
  • 淺談HTML運行原理,所謂的HTML簡單的來說就是一個網頁,雖然第一節就講html原理可能大家會聽不懂,就當是給一個初步印象把,至少大概知道一個網頁的運行流程是怎樣的,下麵上一張圖: 大致的一個html的運行原理就是如圖所示,瀏覽器發送一個http請求,然後首先會解析功能變數名稱(主機名),然後在本地的“c ...
  • 本文最初發表於 "博客園" ,併在 "GitHub" 上持續更新 前端的系列文章 。歡迎在GitHub上關註我,一起入門和進階前端。 以下是正文。 Vue初體驗 新建一個空的項目,引入vue.js文件。寫如下代碼: 顯示效果: 如果我們在控制台輸入 ,頁面會 自動更新 name的值。 下麵來講一下V ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...