国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

談談ES6前后的異步編程

fizz / 1941人閱讀

摘要:回調(diào)函數(shù)這是異步編程最基本的方法。對象對象是工作組提出的一種規(guī)范,目的是為異步編程提供統(tǒng)一接口。誕生后,出現(xiàn)了函數(shù),它將異步編程帶入了一個全新的階段。

更多詳情點擊http://blog.zhangbing.club/Ja...

Javascript 語言的執(zhí)行環(huán)境是“單線程”的,如果沒有異步編程,根本沒法用,非卡死不可。

為了解決這個問題,Javascript語言將任務的執(zhí)行模式分成兩種:同步(Synchronous)和異步(Asynchronous)兩種模式概念很好理解。

ES6 誕生以前,異步編程的方法,大概有下面四種:回調(diào)函數(shù) ,事件監(jiān)聽 ,發(fā)布/訂閱 ,Promise對象。

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

這是異步編程最基本的方法。

假定有兩個函數(shù)f1和f2,后者等待前者的執(zhí)行結果。

  f1();
  f2();

如果f1是一個很耗時的任務,可以考慮改寫f1,把f2寫成f1的回調(diào)函數(shù)。

  function f1(callback){
    setTimeout(function () {
      // f1的任務代碼
      callback();
    }, 1000);
  }

執(zhí)行代碼就變成下面這樣:

f1(f2);

采用這種方式,我們把同步操作變成了異步操作,f1不會堵塞程序運行,相當于先執(zhí)行程序的主要邏輯,將耗時的操作推遲執(zhí)行。

回調(diào)函數(shù)的優(yōu)點是簡單、容易理解和部署,缺點是不利于代碼的閱讀和維護,各個部分之間高度耦合(Coupling),流程會很混亂,而且每個任務只能指定一個回調(diào)函數(shù)。

事件監(jiān)聽

另一種思路是采用事件驅(qū)動模式。任務的執(zhí)行不取決于代碼的順序,而取決于某個事件是否發(fā)生。

還是以f1和f2為例。首先,為f1綁定一個事件(這里采用的jQuery的寫法)。

f1.on("done", f2);

上面這行代碼的意思是,當f1發(fā)生done事件,就執(zhí)行f2。然后,對f1進行改寫:

  function f1(){
    setTimeout(function () {
      // f1的任務代碼
      f1.trigger("done");
    }, 1000);
  }

f1.trigger("done")表示,執(zhí)行完成后,立即觸發(fā)done事件,從而開始執(zhí)行f2。

這種方法的優(yōu)點是比較容易理解,可以綁定多個事件,每個事件可以指定多個回調(diào)函數(shù),而且可以"去耦合"(Decoupling),有利于實現(xiàn)模塊化。缺點是整個程序都要變成事件驅(qū)動型,運行流程會變得很不清晰。

發(fā)布/訂閱

上一節(jié)的"事件",完全可以理解成"信號"。

我們假定,存在一個"信號中心",某個任務執(zhí)行完成,就向信號中心"發(fā)布"(publish)一個信號,其他任務可以向信號中心"訂閱"(subscribe)這個信號,從而知道什么時候自己可以開始執(zhí)行。這就叫做"發(fā)布/訂閱模式"(publish-subscribe pattern),又稱"觀察者模式"(observer pattern)。

這個模式有多種實現(xiàn),下面采用的是Ben Alman的Tiny Pub/Sub,這是jQuery的一個插件。

首先,f2向"信號中心"jQuery訂閱"done"信號。

jQuery.subscribe("done", f2);

然后,f1進行如下改寫:

  function f1(){
    setTimeout(function () {
      // f1的任務代碼
      jQuery.publish("done");
    }, 1000);
  }

jQuery.publish("done")的意思是,f1執(zhí)行完成后,向"信號中心"jQuery發(fā)布"done"信號,從而引發(fā)f2的執(zhí)行。

此外,f2完成執(zhí)行后,也可以取消訂閱(unsubscribe)。

jQuery.unsubscribe("done", f2);

這種方法的性質(zhì)與"事件監(jiān)聽"類似,但是明顯優(yōu)于后者。因為我們可以通過查看"消息中心",了解存在多少信號、每個信號有多少訂閱者,從而監(jiān)控程序的運行。

Promises對象

Promises對象是CommonJS工作組提出的一種規(guī)范,目的是為異步編程提供統(tǒng)一接口。

簡單說,它的思想是,每一個異步任務返回一個Promise對象,該對象有一個then方法,允許指定回調(diào)函數(shù)。比如,f1的回調(diào)函數(shù)f2,可以寫成:

f1().then(f2);

f1要進行如下改寫(這里使用的是jQuery的實現(xiàn)):

  function f1(){
    var dfd = $.Deferred();
    setTimeout(function () {
      // f1的任務代碼
      dfd.resolve();
    }, 500);
    return dfd.promise;
  }

這樣寫的優(yōu)點在于,回調(diào)函數(shù)變成了鏈式寫法,程序的流程可以看得很清楚,而且有一整套的配套方法,可以實現(xiàn)許多強大的功能。

比如,指定多個回調(diào)函數(shù):

f1().then(f2).then(f3);

再比如,指定發(fā)生錯誤時的回調(diào)函數(shù):

f1().then(f2).fail(f3);

而且,它還有一個前面三種方法都沒有的好處:如果一個任務已經(jīng)完成,再添加回調(diào)函數(shù),該回調(diào)函數(shù)會立即執(zhí)行。所以,你不用擔心是否錯過了某個事件或信號。這種方法的缺點就是編寫和理解,都相對比較難。

ES6誕生后,出現(xiàn)了Generator函數(shù),它將 JavaScript 異步編程帶入了一個全新的階段。ES6也將Promise 其寫進了語言標準,統(tǒng)一了用法,原生提供了Promise對象。

故ES6異步編程的方法,大概有兩種:Generator函數(shù),Promise。

Generator函數(shù)

特點: 帶星號function,yield語句 ,next() 獲取下一個yield表達式中yield后的值,擁有遍歷器接口,與for..of可搭配使用

下面代碼中,Generator函數(shù)封裝了一個異步操作,該操作先讀取一個遠程接口,然后從JSON格式的數(shù)據(jù)解析信息。這段代碼非常像同步操作,除了加上了yield命令

var fetch = require("node-fetch");

function * gen() {
    var url = "http://api.github.com/users/github";
    var result = yield fetch(url);
    console.log(result.bio);
}

var g = gen();
var result = g.next();

result.value.then(function(data) {
    return data.json();
}).then(function (data) {
    g.next(data);
});

執(zhí)行過程:

首先執(zhí)行Generator函數(shù),獲取遍歷器對象,然后使用next 方法(第二行),執(zhí)行異步任務的第一階段。由于Fetch模塊返回的是一個Promise對象,因此要用then方法調(diào)用下一個next 方法。

缺點:

可以看到,雖然Generator函數(shù)將異步操作表示得很簡潔,但是流程管理卻不方便(即何時執(zhí)行第一階段、何時執(zhí)行第二階段),即如何實現(xiàn)自動化的流程管理。

補充拓展

可以參考阮一峰的ECMAScript 6 入門用Thunk函數(shù)實現(xiàn)自動化流程管理,對Generator函數(shù)進行拓展,前提是每一個異步操作,都要是Thunk函數(shù),進價就是再用CO模塊來實現(xiàn)自動化流程管理,co模塊其實就是將兩種自動執(zhí)行器(Thunk 函數(shù)和 Promise 對象),包裝成一個模塊。使用 co 的前提條件是,Generator 函數(shù)的yield命令后面,只能是 Thunk 函數(shù)或 Promise 對象。如果數(shù)組或?qū)ο蟮某蓡T,全部都是 Promise 對象,也可以使用 co。后面,ES2017標準引入了async函數(shù),對Generator再“語法升級”, async 函數(shù)是什么?一句話,它就是 Generator 函數(shù)的語法糖。async函數(shù)對 Generator 函數(shù)進行了改進,體現(xiàn)在以下四點:

內(nèi)置執(zhí)行器。

Generator 函數(shù)的執(zhí)行必須靠執(zhí)行器,所以才有了co模塊,而async函數(shù)自帶執(zhí)行器。也就是說,async函數(shù)的執(zhí)行,與普通函數(shù)一模一樣,只要一行。

更好的語義。

async和await,比起星號和yield,語義更清楚了。async表示函數(shù)里有異步操作,await表示緊跟在后面的表達式需要等待結果。

更廣的適用性。

co模塊約定,yield命令后面只能是 Thunk 函數(shù)或 Promise 對象,而async函數(shù)的await命令后面,可以是 Promise 對象和原始類型的值(數(shù)值、字符串和布爾值,但這時等同于同步操作)。

返回值是 Promise。

async函數(shù)的返回值是 Promise 對象,這比 Generator 函數(shù)的返回值是 Iterator 對象方便多了。你可以用then方法指定下一步的操作。進一步說,async函數(shù)完全可以看作多個異步操作,包裝成的一個 Promise 對象,而await命令就是內(nèi)部then命令的語法糖。

Promise

ES6 規(guī)定,Promise對象是一個構造函數(shù),用來生成Promise實例。

下面代碼創(chuàng)造了一個Promise實例。

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 異步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

Promise構造函數(shù)接受一個函數(shù)作為參數(shù),該函數(shù)的兩個參數(shù)分別是resolve和reject。它們是兩個函數(shù),由 JavaScript 引擎提供,不用自己部署。

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)閞esolved時調(diào)用,第二個回調(diào)函數(shù)是Promise對象的狀態(tài)變?yōu)閞ejected時調(diào)用。其中,第二個函數(shù)是可選的,不一定要提供。這兩個函數(shù)都接受Promise對象傳出的值作為參數(shù)。 Promise 的基本用法就談到這,更深入用法,請參考阮一峰的ECMAScript 6 入門

特別需要指出的是在ES6之前,promise是一套規(guī)范和原則,只要設計的庫復合規(guī)范的要求就都可以算是promise, 目前比較流行的promise庫(插件)有q和when,RSVP.js,jQuery的Deferred等。ES6后,將Promise 眾多規(guī)范中的一種寫入語言標準,ES6中的 Promise 是其中一種,各個 Promise 規(guī)范之間有細微的差別(主要是特性上的)

參考來源:

ECMAScript 6 入門

Javascript異步編程的4種方法

文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/95841.html

相關文章

  • JS筆記

    摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。異步編程入門的全稱是前端經(jīng)典面試題從輸入到頁面加載發(fā)生了什么這是一篇開發(fā)的科普類文章,涉及到優(yōu)化等多個方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結思考,循序漸進的理解 TypeScript。 網(wǎng)絡基礎知識之 HTTP 協(xié)議 詳細介紹 HTT...

    rottengeek 評論0 收藏0
  • JavaScript 異步編程四種方式

    摘要:異步編程是每個使用編程的人都會遇到的問題,無論是前端的請求,或是的各種異步。本文就來總結一下常見的四種處理異步編程的方法。利用一種鏈式調(diào)用的方法來組織異步代碼,可以將原來以回調(diào)函數(shù)形式調(diào)用的代碼改為鏈式調(diào)用。 異步編程是每個使用 JavaScript 編程的人都會遇到的問題,無論是前端的 ajax 請求,或是 node 的各種異步 API。本文就來總結一下常見的四種處理異步編程的方法。...

    microelec 評論0 收藏0
  • 談談JavaScript異步代碼優(yōu)化

    摘要:異步問題回調(diào)地獄首先,我們來看下異步編程中最常見的一種問題,便是回調(diào)地獄。同時使用也是異步編程最基礎和核心的一種解決思路。基于,目前也被廣泛運用,其是異步編程的一種解決方案,比傳統(tǒng)的回調(diào)函數(shù)解決方案更合理和強大。 關于 微信公眾號:前端呼啦圈(Love-FED) 我的博客:勞卜的博客 知乎專欄:前端呼啦圈 前言 在實際編碼中,我們經(jīng)常會遇到Javascript代碼異步執(zhí)行的場景...

    chnmagnus 評論0 收藏0
  • 談談 ES6 Promise 對象

    摘要:一般會這樣去寫要在第一個請求成功后才可以執(zhí)行下一步這樣的寫法的原理是,當執(zhí)行一些異步操作時,我們需要知道操作是否已經(jīng)完成,所有當執(zhí)行完成的時候會返回一個回調(diào)函數(shù),表示操作已經(jīng)完成。 前言 開篇首先設想一個日常開發(fā)常常會遇到的需求:在多個接口異步請求數(shù)據(jù),然后利用這些數(shù)據(jù)來進行一系列的操作。一般會這樣去寫: $.ajax({ url: ......, success: f...

    linkin 評論0 收藏0
  • 從async await 報錯Unexpected identifier 談談對上下文理解

    摘要:解決辦法,將箭頭函數(shù)聲明為函數(shù),代碼如下運行結果至此,問題解決。必須在函數(shù)的上下文中。對程序而言有了上下文調(diào)用幀才有一個完整的邏輯過程。 先簡單介紹下async await:   async/await是ES6推出的異步處理方案,目的也很明確:更好的實現(xiàn)異步編程。 詳細見阮大神 ES6入門 現(xiàn)在說說實踐中遇到的問題:使用await報錯Unexpected identifier 先...

    Bryan 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<