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

資訊專欄INFORMATION COLUMN

Javascript異步編程:Callback、Promise、Generator

dadong / 1969人閱讀

摘要:異步過(guò)程控制了解異步的意義之后,我們來(lái)對(duì)比目前主流幾種異步過(guò)程控制方法,探討一下異步編程的最佳實(shí)踐。結(jié)語(yǔ)希望本文對(duì)大家有點(diǎn)幫助,能更深刻的理解異步編程,能寫出更優(yōu)雅更高效的代碼。

同步和異步(Synchronous and Asynchronous)

了解javascript的同學(xué)想必對(duì)同步和異步的概念應(yīng)該都很熟悉了,如果還有不熟悉的同學(xué),我這里舉個(gè)形象的例子,比如我們?cè)缟掀鸫埠笠扇拢簾⑾茨槨⒊栽顼垼较喈?dāng)于我們先燒水,水燒開了再洗臉,洗完臉再吃早飯,三件事順序執(zhí)行,一件干完了再干下一件;而異步相當(dāng)于我們?cè)跓耐瑫r(shí)吃早飯(不洗臉就吃早飯不太衛(wèi)生),吃完早飯?jiān)傧茨槨o@然異步比同步更加高效,省去了很多等待的時(shí)間,同步過(guò)程的執(zhí)行時(shí)間取決于所有行為的總和,而異步過(guò)程的執(zhí)行時(shí)間只取決于最長(zhǎng)的那個(gè)行為,如下圖所示:

由于Javascript是單線程的,同時(shí)只能處理一件事,在上面的例子中這個(gè)單線程就是“我”,比如我不能同時(shí)洗臉和吃早飯一樣。所以為了讓執(zhí)行效率提高,我們要盡量讓這個(gè)線程一直處于忙碌狀態(tài)而不是閑置狀態(tài),就像我們不用干等燒水,可以同時(shí)去做其他事情,而燒水由系統(tǒng)的其他線程去處理(該線程不屬于Javascript)。在計(jì)算機(jī)的世界中,很多I/O密集型的操作是需要等待的,比如網(wǎng)絡(luò)請(qǐng)求、文件讀寫等,所以異步方法在處理這些操作會(huì)更加得心應(yīng)手。

異步過(guò)程控制

了解異步的意義之后,我們來(lái)對(duì)比目前主流幾種異步過(guò)程控制方法,探討一下異步編程的最佳實(shí)踐。

1. Callback 誤區(qū)

首先callback和異步?jīng)]有必然聯(lián)系,callback本質(zhì)就是類型為function的函數(shù)參數(shù),對(duì)于該callback是同步還是異步執(zhí)行則取決于函數(shù)本身。雖然callback常用于異步方法的回調(diào),但其實(shí)有不少同步方法也可以傳入callback,比如最常見的數(shù)組的forEach方法:

var arr = [1, 2, 3];
arr.forEach(function (val) {
  console.log(val);
});
console.log("finish");

// 打印結(jié)果:1,2,3,finish

類似的還有數(shù)組的map, filter, reduce等很多方法。

異步Callback

常見的異步callback如setTimeout中的回調(diào):

setTimeout(function () {
  console.log("time"s up");
}, 1000);
console.log("finish");

// 打印結(jié)果:finish, time"s up

如果我們將延遲時(shí)間改為0,打印結(jié)果仍將是finish, time"s up,因?yàn)楫惒絚allback會(huì)等函數(shù)中的同步方法都執(zhí)行完成后再執(zhí)行。

Callback Hell

在實(shí)際項(xiàng)目中我們經(jīng)常會(huì)遇到這樣的問(wèn)題:下一步操作依賴于上一步操作的結(jié)果,上一步操作又依賴于上上步操作,而每一步操作都是異步的。。這樣遞進(jìn)的層級(jí)多了會(huì)形成很多層callback嵌套,導(dǎo)致代碼可讀性和可維護(hù)性變的很差,形成所謂的Callback Hell,類似這樣:

step1(param, function (result1) {
  step2(result1, function (result2) {
    step3(result2, function (result3) {
      step4(result3, function (result4) {
        done(result4);
      })
    })
  })
})

當(dāng)然在不放棄使用callback的前提下,上面的代碼還是有優(yōu)化空間的,我們可以將它重新組織一下:

step1(param, callbac1);

function callback1(result1){
  step2(result1, callback2);
}

function callback2(result2){
  step3(result2, callback3);
}

function callback3(result3){
  step4(result3, callback4);
}

function callback4(result4){
  done(result4);
}

相當(dāng)于將Callback Hell的橫向深度轉(zhuǎn)化為代碼的縱向高度,變得更接近于我們習(xí)慣的由上到下的同步調(diào)用, 復(fù)雜度沒有變,只是看起來(lái)更清晰了,缺點(diǎn)就是要定義額外的函數(shù)、變量。將這一思想進(jìn)一步延伸就有了下面的Promise。

2. Promise

Promise中文譯為“承諾”,在Javascript中是一個(gè)抽象的概念,代表當(dāng)前沒有實(shí)現(xiàn),但未來(lái)的某個(gè)時(shí)間點(diǎn)會(huì)(也可能不會(huì))實(shí)現(xiàn)的一件事。舉個(gè)實(shí)例化的例子:早上燒水,我給你一個(gè)承諾(Promise),十分鐘后水能燒開,如果一切正常,10分鐘之后水確實(shí)能燒開,代表這個(gè)promise兌現(xiàn)了(fullfilled),但是如果中途停電了,10分鐘水沒燒開,那這個(gè)promise兌現(xiàn)失敗(rejected)。用代碼可以表示為:

const boilWaterInTenMins = new Promise(function (resolve, reject) {
  boiler.work(function (timeSpent) {
    if (timeSpent <= 10) {
      resolve();
    } else {
      reject();
    }
  });
});
兼容性

如果想提高瀏覽器對(duì)Promise的兼容性可以使用babel或者第三方的實(shí)現(xiàn)(參考 github awesome promise)

Promise Chaining

我們?cè)賮?lái)看Promise對(duì)于異步過(guò)程控制有怎樣的提升,還基于上面Callback Hell的例子,如果用Promise實(shí)現(xiàn)會(huì)如何呢?

首先我們需要將step1 ~ done 的函數(shù)用Promise實(shí)現(xiàn)(即返回一個(gè)Promise),然后進(jìn)行一連串的鏈?zhǔn)秸{(diào)用就可以了:

stepOne(param)
  .then((result1) => { return step2(result1) })
  .then((result2) => { return step3(result2) })
  .then((result3) => { return step4(result3) })
  .then((result4) => { return done(result4) })
  .catch(err => handleError(err));

是不是簡(jiǎn)單很多!

Async/Await

如果你不太習(xí)慣Promise的調(diào)用方式,那我們可以用async/await將其轉(zhuǎn)化成更接近同步調(diào)用的方式:

async function main() {
  try {
    var result1 = await step1(param);
    var result2 = await step2(result1);
    var result3 = await step3(result2);
    var result4 = await step4(result3);
    done(result4);
  } catch (err) {
    handleError(err);
  }
}

main();
3. Generator

Generator是一個(gè)更加抽象的概念,要弄懂什么是Generator首先要理解另外幾個(gè)概念I(lǐng)terable Protocol(可迭代協(xié)議),Iterator Protocol(迭代器協(xié)議)和 Iterator(迭代器)。

Iterable Protocol

Iterable Protocol 的特點(diǎn)可以概括為:

用于定義javascript對(duì)象的迭代行為

對(duì)象本身或者原型鏈上需要有一個(gè)名為Symbol.iterator的方法

該方法不接收任何參數(shù),且返回一個(gè)Iterator

Iterable的對(duì)象可以使用for...of遍歷

Javascript Array就實(shí)現(xiàn)了Iterable Protocol,除了常規(guī)的取值方式,我們也可以利用array的Symbol.iterator

var arr = [1, 2, 3];
var iterator = arr[Symbol.iterator]();
iterator.next(); // {value: 1, done: false}

我們也可以修改Array默認(rèn)的迭代方式,比如返回兩倍的值:

Array.prototype[Symbol.iterator] = function () {
  var nextIndex = 0;
  var self = this;
  return {
    next: function () {
      return nextIndex < self.length ?
        { value: self[nextIndex++] * 2, done: false } :
        { done: true }
    }
  };
}

for(let el of [1, 2, 3]){
  console.log(el);
}
// 輸出:2,4,6
Iterator Protocol

Iterator Protocol 的特點(diǎn)可以概括為:

一種產(chǎn)生一個(gè)序列值(有限或無(wú)限)的標(biāo)準(zhǔn)方式

實(shí)現(xiàn)一個(gè)next方法

next方法返回的對(duì)象為 {value: any, done: boolean}

value為返回值,donetrue時(shí)value可以省略

donetrue表示迭代結(jié)束,此時(shí)value表示最終返回值

donefalse,則可以繼續(xù)迭代,產(chǎn)生下一個(gè)值

Iterator

顯然Iterator就是實(shí)現(xiàn)了Iterator Protocol的對(duì)象。

Generator

理解上面幾個(gè)概念后,理解Generator就簡(jiǎn)單多了,generator的特點(diǎn)可概括為:

同時(shí)實(shí)現(xiàn)Iterable Protocol和Iterator Protocol,所以Genrator即是一個(gè)iterable的對(duì)象又是一個(gè)iterator

Generator由 generator function 生成

最簡(jiǎn)單的generator function比如:

function* gen() {
  var x = yield 5 + 6;
}

var myGen = gen(); // myGen 就是一個(gè)generator

我們可以調(diào)用next方法來(lái)獲得yield表達(dá)式的值:

myGen.next(); // { value: 11, done: false }

但此時(shí)x并沒有被賦值,可以想象成javascript執(zhí)行完 yield 5 + 6 就停住了,為了繼續(xù)執(zhí)行賦值操作我們需要再次調(diào)用next,并將得到的值回傳:

function* gen() {
  var x = yield 5 + 6;
  console.log(x); // 11
}

var myGen = gen();
console.log(myGen.next()); // { value: 11, done: false }
console.log(myGen.next(11)); // { value: undefined, done: true }

說(shuō)了這么多,generator和異步到底有什么關(guān)系呢?我們來(lái)看Promise + Generator 實(shí)現(xiàn)的異步控制(step1 ~ done 返回Promise):

genWrap(function* () {
  var result1 = yield step1(param);
  var result2 = yield step2(result1);
  var result3 = yield step3(result2);
  var result4 = yield step4(result3);
  var result5 = yield done(result4);
});

function genWrap(genFunc) {
  var generator = genFunc();

  function handle(yielded) {
    if (!yielded.done) {
      yielded.value.then(function (result) {
        return handle(generator.next(result));
      });
    }
  }

  return handle(generator.next());
}

和async/await類似,這種實(shí)現(xiàn)也將異步方法轉(zhuǎn)化成了同步的寫法,實(shí)際上這就是 ES7中async/await的實(shí)現(xiàn)原理(將genWrap替換為async,將yield替換成await)。

結(jié)語(yǔ)

希望本文對(duì)大家有點(diǎn)幫助,能更深刻的理解javascript異步編程,能寫出更優(yōu)雅更高效的代碼。有錯(cuò)誤歡迎指正。新年快樂(lè)!

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/101542.html

相關(guān)文章

  • 我了解到的JavaScript異步編程

    摘要:接下來(lái)我們看下三類異步編程的實(shí)現(xiàn)。事件監(jiān)聽事件發(fā)布訂閱事件監(jiān)聽是一種非常常見的異步編程模式,它是一種典型的邏輯分離方式,對(duì)代碼解耦很有用處。 一、 一道面試題 前段時(shí)間面試,考察比較多的是js異步編程方面的相關(guān)知識(shí)點(diǎn),如今,正好輪到自己分享技術(shù),所以想把js異步編程學(xué)習(xí)下,做個(gè)總結(jié)。下面這個(gè)demo 概括了大多數(shù)面試過(guò)程中遇到的問(wèn)題: for(var i = 0; i < 3; i++...

    RichardXG 評(píng)論0 收藏0
  • Node.js 異步異聞錄

    摘要:的異步完成整個(gè)異步環(huán)節(jié)的有事件循環(huán)觀察者請(qǐng)求對(duì)象以及線程池。執(zhí)行回調(diào)組裝好請(qǐng)求對(duì)象送入線程池等待執(zhí)行,實(shí)際上是完成了異步的第一部分,回調(diào)通知是第二部分。異步編程是首個(gè)將異步大規(guī)模帶到應(yīng)用層面的平臺(tái)。 showImg(https://segmentfault.com/img/remote/1460000011303472); 本文首發(fā)在個(gè)人博客:http://muyunyun.cn/po...

    zzbo 評(píng)論0 收藏0
  • Javascript中的異步編程

    摘要:接下來(lái),我們一起來(lái)看看中的異步編程,具體有哪幾種。實(shí)現(xiàn)異步編程的方法一回調(diào)函數(shù)上面不止一次提到了回調(diào)函數(shù)。它是異步編程中,最基本的方法。四對(duì)象接下來(lái),我們聊聊與相關(guān)的異步編程方法,對(duì)象。 showImg(https://segmentfault.com/img/bVbneWy?w=1600&h=1200); 前言 最近,小伙伴S 問(wèn)了我一段代碼: const funB = (value...

    wemall 評(píng)論0 收藏0
  • 談?wù)?em>JavaScript異步代碼優(yōu)化

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

    chnmagnus 評(píng)論0 收藏0
  • 探索Javascript 異步編程

    摘要:因?yàn)闉g覽器環(huán)境里是單線程的,所以異步編程在前端領(lǐng)域尤為重要。除此之外,它還有兩個(gè)特性,使它可以作為異步編程的完整解決方案函數(shù)體內(nèi)外的數(shù)據(jù)交換和錯(cuò)誤處理機(jī)制。 showImg(https://segmentfault.com/img/bVz9Cy); 在我們?nèi)粘>幋a中,需要異步的場(chǎng)景很多,比如讀取文件內(nèi)容、獲取遠(yuǎn)程數(shù)據(jù)、發(fā)送數(shù)據(jù)到服務(wù)端等。因?yàn)闉g覽器環(huán)境里Javascript是單線程的,...

    Salamander 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<