最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

ES6 javascript的異步操作實(shí)例詳解

 更新時(shí)間:2017年10月30日 09:43:27   作者:專注前端30年  
這篇文章主要介紹了ES6 javascript的異步操作,結(jié)合實(shí)例形式分析了ES5中異步操作的概念、原理、使用方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下

本文實(shí)例講述了ES6 javascript的異步操作。分享給大家供大家參考,具體如下:

異步編程對(duì) JavaScript 語(yǔ)言太重要。 Javascript 語(yǔ)言的執(zhí)行環(huán)境是“ 單線程” 的, 如果沒(méi)有異步編程, 根本沒(méi)法用, 非卡死不可。

ES6 誕生以前, 異步編程的方法, 大概有下面四種。

① 回調(diào)函數(shù)
② 事件監(jiān)聽
③ 發(fā)布 / 訂閱
④ Promise 對(duì)象

ES6 將 JavaScript 異步編程帶入了一個(gè)全新的階段, ES7 的Async函數(shù)更是提出了異步編程的終極解決方案。

一、基本概念

1. 異步

所謂 " 異步 ",簡(jiǎn)單說(shuō)就是一個(gè)任務(wù)分成兩段, 先執(zhí)行第一段, 然后轉(zhuǎn)而執(zhí)行其他任務(wù), 等做好了準(zhǔn)備, 再回過(guò)頭執(zhí)行第二段。

比如, 有一個(gè)任務(wù)是讀取文件進(jìn)行處理, 任務(wù)的第一段是向操作系統(tǒng)發(fā)出請(qǐng)求, 要求讀取文件。 然后, 程序執(zhí)行其他任務(wù), 等到操作系統(tǒng)返回文件,再接著執(zhí)行任務(wù)的第二段( 處理文件)。 這種不連續(xù)的執(zhí)行, 就叫做異步。

相應(yīng)地, 連續(xù)的執(zhí)行就叫做同步。 由于是連續(xù)執(zhí)行, 不能插入其他任務(wù), 所以操作系統(tǒng)從硬盤讀取文件的這段時(shí)間, 程序只能干等著。

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

JavaScript 語(yǔ)言對(duì)異步編程的實(shí)現(xiàn), 就是回調(diào)函數(shù)。 所謂回調(diào)函數(shù), 就是把任務(wù)的第二段單獨(dú)寫在一個(gè)函數(shù)里面, 等到重新執(zhí)行這個(gè)任務(wù)的時(shí)候, 就直接調(diào)用這個(gè)函數(shù)。 它的英語(yǔ)名字 callback, 直譯過(guò)來(lái)就是 " 重新調(diào)用 "。

讀取文件進(jìn)行處理, 是這樣寫的。

fs.readFile('/etc/passwd', function(err, data) {
  if(err) throw err;
  console.log(data);
});

上面代碼中, readFile 函數(shù)的第二個(gè)參數(shù), 就是回調(diào)函數(shù), 也就是任務(wù)的第二段。 等到操作系統(tǒng)返回了 / etc / passwd這個(gè)文件以后, 回調(diào)函數(shù)才會(huì)執(zhí)行。

一個(gè)有趣的問(wèn)題是, 為什么 Node.js 約定, 回調(diào)函數(shù)的第一個(gè)參數(shù), 必須是錯(cuò)誤對(duì)象 err( 如果沒(méi)有錯(cuò)誤, 該參數(shù)就是 null)? 原因是執(zhí)行分成兩段, 在這兩段之間拋出的錯(cuò)誤, 程序無(wú)法捕捉, 只能當(dāng)作參數(shù), 傳入第二段。

3. Promise

回調(diào)函數(shù)本身并沒(méi)有問(wèn)題, 它的問(wèn)題出現(xiàn)在多個(gè)回調(diào)函數(shù)嵌套。 假定讀取 A 文件之后, 再讀取 B 文件, 代碼如下。

fs.readFile(fileA, function(err, data) {
  fs.readFile(fileB, function(err, data) {
    // ...
  });
});

不難想象, 如果依次讀取多個(gè)文件, 就會(huì)出現(xiàn)多重嵌套。 代碼不是縱向發(fā)展, 而是橫向發(fā)展, 很快就會(huì)亂成一團(tuán), 無(wú)法管理。 這種情況就稱為 " 回調(diào)函數(shù)噩夢(mèng) " ( callback hell )。

Promise 就是為了解決這個(gè)問(wèn)題而提出的。 它不是新的語(yǔ)法功能, 而是一種新的寫法, 允許將回調(diào)函數(shù)的嵌套, 改成鏈?zhǔn)秸{(diào)用。 采用 Promise, 連續(xù)讀取多個(gè)文件, 寫法如下。

var readFile = require('fs-readfile-promise');
readFile(fileA)
  .then(function(data) {
    console.log(data.toString());
  })
  .then(function() {
    return readFile(fileB);
  })
  .then(function(data) {
    console.log(data.toString());
  })
  .catch(function(err) {
    console.log(err);
  });

上面代碼中, 我使用了 fs - readfile - promise 模塊, 它的作用就是返回一個(gè) Promise 版本的 readFile 函數(shù)。 Promise 提供 then 方法加載回調(diào)函數(shù),catch 方法捕捉執(zhí)行過(guò)程中拋出的錯(cuò)誤。
可以看到, Promise 的寫法只是回調(diào)函數(shù)的改進(jìn), 使用 then 方法以后, 異步任務(wù)的兩段執(zhí)行看得更清楚了, 除此以外, 并無(wú)新意。
Promise 的最大問(wèn)題是代碼冗余, 原來(lái)的任務(wù)被 Promise 包裝了一下, 不管什么操作, 一眼看去都是一堆 then, 原來(lái)的語(yǔ)義變得很不清楚。

那么, 有沒(méi)有更好的寫法呢?

二、Generator 函數(shù)

1. 協(xié)程

傳統(tǒng)的編程語(yǔ)言, 早有異步編程的解決方案( 其實(shí)是多任務(wù)的解決方案)。 其中有一種叫做 " 協(xié)程 "(coroutine), 意思是多個(gè)線程互相協(xié)作, 完成異步任務(wù)。

協(xié)程有點(diǎn)像函數(shù), 又有點(diǎn)像線程。 它的運(yùn)行流程大致如下。

第一步, 協(xié)程 A 開始執(zhí)行。
第二步, 協(xié)程 A 執(zhí)行到一半, 進(jìn)入暫停, 執(zhí)行權(quán)轉(zhuǎn)移到協(xié)程 B。
第三步,( 一段時(shí)間后) 協(xié)程 B 交還執(zhí)行權(quán)。
第四步, 協(xié)程 A 恢復(fù)執(zhí)行。

上面流程的協(xié)程 A, 就是異步任務(wù), 因?yàn)樗殖蓛啥危?或多段) 執(zhí)行。

舉例來(lái)說(shuō), 讀取文件的協(xié)程寫法如下。

function* asyncJob() {
  // ... 其他代碼
  var f = yield readFile(fileA);
  // ... 其他代碼
}

上面代碼的函數(shù)asyncJob是一個(gè)協(xié)程, 它的奧妙就在其中的yield命令。 它表示執(zhí)行到此處, 執(zhí)行權(quán)將交給其他協(xié)程。 也就是說(shuō), yield命令是異步兩個(gè)階段的分界線。

協(xié)程遇到y(tǒng)ield命令就暫停, 等到執(zhí)行權(quán)返回, 再?gòu)臅和5牡胤嚼^續(xù)往后執(zhí)行。 它的最大優(yōu)點(diǎn), 就是代碼的寫法非常像同步操作, 如果去除 yield 命令,簡(jiǎn)直一模一樣。

2. Generator 函數(shù)的概念

enerator 函數(shù)是協(xié)程在 ES6 的實(shí)現(xiàn), 最大特點(diǎn)就是可以交出函數(shù)的執(zhí)行權(quán)( 即暫停執(zhí)行)。

整個(gè) Generator 函數(shù)就是一個(gè)封裝的異步任務(wù), 或者說(shuō)是異步任務(wù)的容器。 異步操作需要暫停的地方, 都用yield語(yǔ)句注明。 Generator 函數(shù)的執(zhí)行方法

如下。

function* gen(x) {
  var y = yield x + 2;
  return y;
}
var g = gen(1);
g.next() // { value: 3, done: false }
g.next() // { value: undefined, done: true }

上面代碼中, 調(diào)用 Generator 函數(shù), 會(huì)返回一個(gè)內(nèi)部指針( 即遍歷器) g。 這是 Generator 函數(shù)不同于普通函數(shù)的另一個(gè)地方, 即執(zhí)行它不會(huì)返回結(jié)果, 返回的是指針對(duì)象。 調(diào)用指針 g 的 next 方法, 會(huì)移動(dòng)內(nèi)部指針( 即執(zhí)行異步任務(wù)的第一段), 指向第一個(gè)遇到的 yield 語(yǔ)句, 上例是執(zhí)行到x + 2 為止。

換言之, next 方法的作用是分階段執(zhí)行 Generator 函數(shù)。 每次調(diào)用 next 方法, 會(huì)返回一個(gè)對(duì)象, 表示當(dāng)前階段的信息( value 屬性和 done 屬性)。 value屬性是 yield 語(yǔ)句后面表達(dá)式的值, 表示當(dāng)前階段的值; done 屬性是一個(gè)布爾值, 表示 Generator 函數(shù)是否執(zhí)行完畢, 即是否還有下一個(gè)階段。

3. Generator 函數(shù)的數(shù)據(jù)交換和錯(cuò)誤處理

Generator 函數(shù)可以暫停執(zhí)行和恢復(fù)執(zhí)行, 這是它能封裝異步任務(wù)的根本原因。 除此之外, 它還有兩個(gè)特性, 使它可以作為異步編程的完整解決方案:函數(shù)體內(nèi)外的數(shù)據(jù)交換和錯(cuò)誤處理機(jī)制。

next 方法返回值的 value 屬性, 是 Generator 函數(shù)向外輸出數(shù)據(jù); next 方法還可以接受參數(shù), 這是向 Generator 函數(shù)體內(nèi)輸入數(shù)據(jù)。

function* gen(x) {
  var y = yield x + 2;
  return y;
}
var g = gen(1);
g.next() // { value: 3, done: false }
g.next(2) // { value: 2, done: true }

上面代碼中, 第一個(gè) next 方法的 value 屬性, 返回表達(dá)式x + 2 的值( 3)。 第二個(gè) next 方法帶有參數(shù) 2, 這個(gè)參數(shù)可以傳入 Generator 函數(shù), 作為上個(gè)階段異步任務(wù)的返回結(jié)果, 被函數(shù)體內(nèi)的變量 y 接收。 因此, 這一步的 value 屬性, 返回的就是 2( 變量 y 的值)。

Generator 函數(shù)內(nèi)部還可以部署錯(cuò)誤處理代碼, 捕獲函數(shù)體外拋出的錯(cuò)誤。

function* gen(x) {
  try {
    var y = yield x + 2;
  } catch(e) {
    console.log(e);
  }
  return y;
}
var g = gen(1);
g.next();
g.throw(' 出錯(cuò)了 ');

上面代碼的最后一行, Generator 函數(shù)體外, 使用指針對(duì)象的throw 方法拋出的錯(cuò)誤, 可以被函數(shù)體內(nèi)的try...catch 代碼塊捕獲。 這意味著, 出錯(cuò)的代碼與處理錯(cuò)誤的代碼, 實(shí)現(xiàn)了時(shí)間和空間上的分離, 這對(duì)于異步編程無(wú)疑是很重要的。

4. 異步任務(wù)的封裝

下面看看如何使用 Generator 函數(shù), 執(zhí)行一個(gè)真實(shí)的異步任務(wù)。

var fetch = require('node-fetch');
function* gen() {
  var url = 'https://api.github.com/users/github';
  var result = yield fetch(url);
  console.log(result.bio);
}

上面代碼中, Generator 函數(shù)封裝了一個(gè)異步操作, 該操作先讀取一個(gè)遠(yuǎn)程接口, 然后從 JSON 格式的數(shù)據(jù)解析信息。 就像前面說(shuō)過(guò)的, 這段代碼非常像同步操作, 除了加上了 yield 命令。

執(zhí)行這段代碼的方法如下。

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

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

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

更多相關(guān)內(nèi)容可查看本站專題:《ECMAScript6(ES6)入門教程》、《JavaScript數(shù)組操作技巧總結(jié)》、《JavaScript字符與字符串操作技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript錯(cuò)誤與調(diào)試技巧總結(jié)》及《javascript面向?qū)ο笕腴T教程

希望本文所述對(duì)大家基于ECMAScript的程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • 微信小程序?qū)崿F(xiàn)簡(jiǎn)單聊天室

    微信小程序?qū)崿F(xiàn)簡(jiǎn)單聊天室

    這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)簡(jiǎn)單聊天室,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • uniapp使用第三方UI庫(kù)uview-plus的方法

    uniapp使用第三方UI庫(kù)uview-plus的方法

    uview-plus是uni-app全面兼容nvue的uni-app生態(tài)框架,全面的組件和便捷的工具會(huì)讓您信手拈來(lái),下面這篇文章主要給大家介紹了關(guān)于uniapp使用第三方UI庫(kù)uview-plus的方法,需要的朋友可以參考下
    2023-04-04
  • JavaScript的設(shè)計(jì)模式經(jīng)典之代理模式

    JavaScript的設(shè)計(jì)模式經(jīng)典之代理模式

    代理模式的定義是把對(duì)一個(gè)對(duì)象的訪問(wèn), 交給另一個(gè)代理對(duì)象來(lái)操作。接下來(lái)通過(guò)本文給大家介紹JavaScript的設(shè)計(jì)模式之代理模式,感興趣的朋友一起學(xué)習(xí)吧
    2016-02-02
  • 淺聊一下為什么能用RxJS取代Redux

    淺聊一下為什么能用RxJS取代Redux

    本文我們將和大家淺聊一下為什么能用RxJS取代Redux,RxJS 在現(xiàn)在的前端用比較少,但是 RxJS 作為響應(yīng)式和函數(shù)式編程的集大成者,似乎被前端開發(fā)者遺忘,可能是學(xué)習(xí)難度大,可能是有更加方便的解決方案,需要的朋友可以參考下
    2024-02-02
  • 基于JavaScript創(chuàng)建動(dòng)態(tài)Dom

    基于JavaScript創(chuàng)建動(dòng)態(tài)Dom

    這篇文章主要介紹了基于JavaScript創(chuàng)建動(dòng)態(tài)Dom的相關(guān)資料,需要的朋友可以參考下
    2015-12-12
  • avalonjs制作響應(yīng)式瀑布流特效

    avalonjs制作響應(yīng)式瀑布流特效

    瀑布流主要應(yīng)用在圖片展示頁(yè)面上。如果有一大批圖片需要展示,原始圖片尺寸不一致,又希望每張圖片都能不剪裁,完整顯示,那么就要給圖片規(guī)定一個(gè)寬度,解放它們的高度。利用網(wǎng)頁(yè)高度不限這個(gè)特性,充分利用頁(yè)面的空間,盡可能的展示多的圖片。下面我們就來(lái)詳細(xì)探討下
    2015-05-05
  • fastadmin如何讓后臺(tái)的日期顯示成年月日格式(推薦)

    fastadmin如何讓后臺(tái)的日期顯示成年月日格式(推薦)

    FastAdmin是一款基于ThinkPHP5+Bootstrap的極速后臺(tái)開發(fā)框架,本文給大家介紹fastadmin的后臺(tái)時(shí)間戳字段如何顯示成年月日的日期格式,感興趣的朋友跟隨小編一起看看吧
    2023-10-10
  • 圖片無(wú)縫滾動(dòng)代碼(向左/向下/向上)

    圖片無(wú)縫滾動(dòng)代碼(向左/向下/向上)

    想必大家都注意到marquee的不循環(huán)滾動(dòng),所以出現(xiàn)了很多替代腳本,接下來(lái)為大家詳細(xì)介紹下:向左滾動(dòng)/圖片左無(wú)縫滾動(dòng)/向下滾動(dòng)/圖片下無(wú)縫滾動(dòng)/向上滾動(dòng)的實(shí)現(xiàn)
    2013-04-04
  • easyui combobox開啟搜索自動(dòng)完成功能的實(shí)例代碼

    easyui combobox開啟搜索自動(dòng)完成功能的實(shí)例代碼

    下面小編就為大家?guī)?lái)一篇easyui combobox開啟搜索自動(dòng)完成功能的實(shí)例代碼。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-11-11
  • js 得到文件后綴(通過(guò)正則實(shí)現(xiàn))

    js 得到文件后綴(通過(guò)正則實(shí)現(xiàn))

    使用js獲取文件的后綴,有個(gè)不錯(cuò)的正則,大家可以借用下,具體如下,感興趣的朋友可以參考下哈,希望對(duì)大家有所幫助
    2013-07-07

最新評(píng)論

邯郸县| 长岭县| 股票| 保亭| 清远市| 泽库县| 安顺市| 阜新市| 蓬莱市| 周至县| 南涧| 迁西县| 北票市| 北辰区| 开化县| 五莲县| 浦北县| 连州市| 卢湾区| 喜德县| 张掖市| 新乐市| 巫溪县| 涪陵区| 隆昌县| 汉源县| 神木县| 靖远县| 新巴尔虎左旗| 岳普湖县| 兴国县| 揭东县| 项城市| 陆川县| 鸡东县| 额尔古纳市| 新野县| 安乡县| 洛阳市| 博爱县| 太白县|