成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Promise到底解決了什么問題?

yibinnn / 2042人閱讀

摘要:我的博客大家都知道解決了回調(diào)地獄的問題。這就是異步的嵌套帶來的可讀性的問題,它是由異步的運(yùn)行機(jī)制引起的。在與第三方團(tuán)隊(duì)溝通之后問題得到了解決。這不但使代碼變得臃腫不堪,還進(jìn)一步加劇了可讀性的問題。的特征保證了可以解決信任問題。

我的github博客 https://github.com/zhuanyongxigua/blog

大家都知道Promise解決了回調(diào)地獄的問題。說到回調(diào)地獄,很容易想到下面這個(gè)容易讓人產(chǎn)生誤解的圖片

可回調(diào)地獄到底是什么?它到底哪里有問題?是因?yàn)榍短撞缓每催€是讀起來不方便?

首先我們要想想,嵌套到底哪里有問題?

舉個(gè)例子:

function a() {
  function b() {
    function c() {
      function d() {}
      d();
    }
    c();
  }
  b();
}
a();

這也是嵌套,雖然好像不是特別美觀,可我們并不會(huì)覺得這有什么問題吧?因?yàn)槲覀兘?jīng)常會(huì)寫出類似的代碼。

在這個(gè)例子中的嵌套的問題僅僅是縮進(jìn)的問題,而縮進(jìn)除了會(huì)讓代碼變寬可能會(huì)造成讀代碼的一點(diǎn)不方便之外,并沒有什么其他的問題。如果僅僅是這樣,為什么不叫“縮進(jìn)地獄”或“嵌套地獄”?

把回調(diào)地獄完全理解成縮進(jìn)的問題是常見的對(duì)回調(diào)地獄的誤解。要回到“回調(diào)地獄”這個(gè)詞語上面來,它的重點(diǎn)就在于“回調(diào)”,而“回調(diào)”在JS中應(yīng)用最多的場(chǎng)景當(dāng)然就是異步編程了。

所以,“回調(diào)地獄”所說的嵌套其實(shí)是指異步的嵌套。它帶來了兩個(gè)問題:可讀性的問題和信任問題。

可讀性的問題

這是一個(gè)在網(wǎng)上隨便搜索的關(guān)于執(zhí)行順序的面試題:

for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(new Date, i);
  }, 1000);
}

console.log(new Date, i);

答案是什么大家自己想吧,這不是重點(diǎn)。重點(diǎn)是,你要想一會(huì)兒吧?

一個(gè)整潔的回調(diào):

listen( "click", function handler( evt){ 
  setTimeout( function request(){ 
    ajax( "http:// some. url. 1", function response( text){ 
      if (text == "hello") { 
        handler(); 
      } else if (text == "world") { 
        request(); 
      } 
    }); 
  }, 500); 
});

如果異步的嵌套都是這樣干凈整潔,那“回調(diào)地獄”給程序猿帶來的傷害馬上就會(huì)減少很多。

可我們實(shí)際在寫業(yè)務(wù)邏輯的時(shí)候,真實(shí)的情況應(yīng)該是這樣的:

listen( "click", function handler(evt){ 
  doSomething1();
  doSomething2();
  doSomething3();
  doSomething4();
  setTimeout( function request(){ 
    doSomething8();
    doSomething9();
    doSomething10();
    ajax( "http:// some. url. 1", function response( text){ 
      if (text == "hello") { 
        handler(); 
      } else if (text == "world") { 
        request(); 
      } 
    }); 
    doSomething11();
    doSomething12();
    doSomething13();
  }, 500); 
  doSomething5();
  doSomething6();
  doSomething7();
});

這些“doSomething”有些是異步的,有些是同步。這樣的代碼讀起來會(huì)非常的吃力,因?yàn)槟阋煌5乃伎妓麄兊膱?zhí)行順序,并且還要記在腦袋里面。這就是異步的嵌套帶來的可讀性的問題,它是由異步的運(yùn)行機(jī)制引起的。

信任問題

這里主要用異步請(qǐng)求討論。我們?cè)谧鯝JAX請(qǐng)求的時(shí)候,一般都會(huì)使用一些第三方的工具庫(即便是自己封裝的,也可以在一定程度上理解成第三方的),這就會(huì)帶來一個(gè)問題:這些工具庫是否百分百的可靠?

一個(gè)來自《YDKJS》的例子:一個(gè)程序員開發(fā)了一個(gè)付款的系統(tǒng),它良好的運(yùn)行了很長時(shí)間。突然有一天,一個(gè)客戶在付款的時(shí)候信用卡被連續(xù)刷了五次。這名程序員在調(diào)查了以后發(fā)現(xiàn),一個(gè)第三方的工具庫因?yàn)槟承┰虬迅犊罨卣{(diào)執(zhí)行了五次。在與第三方團(tuán)隊(duì)溝通之后問題得到了解決。

故事講完了,可問題真的解決了嗎?是否還能夠充分的信任這個(gè)工具庫?信任依然要有,可完善必要的檢查和錯(cuò)誤處理勢(shì)在必行。當(dāng)我們解決了這個(gè)問題,由于它的啟發(fā),我們還會(huì)聯(lián)想到其他的問題,比如沒有調(diào)用回調(diào)。

再繼續(xù)想,你會(huì)發(fā)現(xiàn),這樣的問題還要好多好多。總結(jié)一下可能會(huì)出現(xiàn)的問題:

回調(diào)過早(一般是異步被同步調(diào)用);

回調(diào)過晚或沒有回調(diào);

回調(diào)次數(shù)過多;

等等

加上了這些檢查,強(qiáng)壯之后的代碼可能是這樣的:

listen( "click", function handler( evt){ 
  check1();
  doSomething1();
  setTimeout( function request(){ 
    check2();
    doSomething3();
    ajax( "http:// some. url. 1", function response( text){ 
      if (text == "hello") { 
        handler(); 
      } else if (text == "world") { 
        request(); 
      } 
    }); 
    doSomething4();
  }, 500); 
  doSomething2();
});

我們都清楚的知道,實(shí)際的check要比這里看起來的復(fù)雜的多,而且很多很難復(fù)用。這不但使代碼變得臃腫不堪,還進(jìn)一步加劇了可讀性的問題。

雖然這些錯(cuò)誤出現(xiàn)的概率不大,但我們依然必須要處理。

這就是異步嵌套帶來的信任問題,它的問題的根源在于控制反轉(zhuǎn)??刂品崔D(zhuǎn)在面向?qū)ο笾械膽?yīng)用是依賴注入,實(shí)現(xiàn)了模塊間的解耦。而在回調(diào)中,它就顯得沒有那么善良了,控制權(quán)被交給了第三方,由第三方?jīng)Q定什么時(shí)候調(diào)用回調(diào)以及如何調(diào)用回調(diào)。

一些解決信任問題的嘗試

加一個(gè)處理錯(cuò)誤的回調(diào)

function success(data) { 
  console. log(data); 
} 
function failure(err) { 
  console. error( err ); 
} 
ajax( "http:// some. url. 1", success, failure );

nodejs的error-first

function response(err, data) { 
  if (err) { 
    console. error( err ); 
  } 
  else { 
    console. log( data ); 
  } 
} 
ajax( "http:// some. url. 1", response );

這兩種方式解決了一些問題,減少了一些工作量, 但是依然沒有徹底解決問題。首先它們的可復(fù)用性依然不強(qiáng),其次,如回調(diào)被多次調(diào)用的問題依然無法解決。

Promise如何解決這兩個(gè)問題

Promise已經(jīng)是原生支持的API了,它已經(jīng)被加到了JS的規(guī)范里面,在各大瀏覽器中的運(yùn)行機(jī)制是相同的。這樣就保證了它的可靠。

如何解決可讀性的問題

這一點(diǎn)不用多說,用過Promise的人很容易明白。Promise的應(yīng)用相當(dāng)于給了你一張可以把解題思路清晰記錄下來的草稿紙,你不在需要用腦子去記憶執(zhí)行順序。

如何解決信任問題

Promise并沒有取消控制反轉(zhuǎn),而是把反轉(zhuǎn)出去的控制再反轉(zhuǎn)一次,也就是反轉(zhuǎn)了控制反轉(zhuǎn)。

這種機(jī)制有點(diǎn)像事件的觸發(fā)。它與普通的回調(diào)的方式的區(qū)別在于,普通的方式,回調(diào)成功之后的操作直接寫在了回調(diào)函數(shù)里面,而這些操作的調(diào)用由第三方控制。在Promise的方式中,回調(diào)只負(fù)責(zé)成功之后的通知,而回調(diào)成功之后的操作放在了then的回調(diào)里面,由Promise精確控制。

Promise有這些特征:只能決議一次,決議值只能有一個(gè),決議之后無法改變。任何then中的回調(diào)也只會(huì)被調(diào)用一次。Promise的特征保證了Promise可以解決信任問題。

對(duì)于回調(diào)過早的問題,由于Promise只能是異步的,所以不會(huì)出現(xiàn)異步的同步調(diào)用。即便是在決議之前的錯(cuò)誤,也是異步的,并不是會(huì)產(chǎn)生同步(調(diào)用過早)的困擾。

var a = new Promise((resolve, reject) => {
  var b = 1 + c;  // ReferenceError: c is not defined,錯(cuò)誤會(huì)在下面的a打印出來之后報(bào)出。
  resolve(true);
})
console.log(1, a);
a.then(res => {
  console.log(2, res);
})
.catch(err => {
  console.log(err);
})

對(duì)于回調(diào)過晚或沒有調(diào)用的問題,Promise本身不會(huì)回調(diào)過晚,只要決議了,它就會(huì)按照規(guī)定運(yùn)行。至于服務(wù)器或者網(wǎng)絡(luò)的問題,并不是Promise能解決的,一般這種情況會(huì)使用Promise的競(jìng)態(tài)APIPromise.race加一個(gè)超時(shí)的時(shí)間:

function timeoutPromise(delay) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      reject("Timeout!");
    }, delay);
  });
}

Promise.race([doSomething(), timeoutPromise(3000)])
.then(...)
.catch(...);

對(duì)于回調(diào)次數(shù)太少或太多的問題,由于Promise只能被決議一次,且決議之后無法改變,所以,即便是多次回調(diào),也不會(huì)影響結(jié)果,決議之后的調(diào)用都會(huì)被忽略。

參考資料:

You Don"t Know JS: Async & Performance

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/97402.html

相關(guān)文章

  • 在非阻塞IO下的nodejs下的同步并行 ES6的 promise 從入門深入(一)

    摘要:我們先介紹一下中的的一些調(diào)用再結(jié)合的應(yīng)用逐步深入。這就是一些簡(jiǎn)單的的調(diào)用看起來不多,但是靠這個(gè)真得解決了許多必須同步并行的環(huán)境本身是一個(gè)對(duì)象在開始支持。存在兩個(gè)回調(diào)函數(shù)根據(jù)個(gè)人的需求進(jìn)行處理。 什么是promise?為什么要在nodejs中使用promise?使用promise到底有什么好處呢?實(shí)在太多了,一一說來不如直接上實(shí)戰(zhàn)。我們先介紹一下nodejs中的promise的一些調(diào)用....

    luffyZh 評(píng)論0 收藏0
  • 理解 JavaScript 的 async/await

    摘要:因?yàn)楹瘮?shù)返回一個(gè)對(duì)象,所以可以用于等待一個(gè)函數(shù)的返回值這也可以說是在等函數(shù),但要清楚,它等的實(shí)際是一個(gè)返回值。幫我們干了啥作個(gè)簡(jiǎn)單的比較上面已經(jīng)說明了會(huì)將其后的函數(shù)函數(shù)表達(dá)式或的返回值封裝成一個(gè)對(duì)象,而會(huì)等待這個(gè)完成,并將其的結(jié)果返回出來。 隨著 Node 7 的發(fā)布,越來越多的人開始研究據(jù)說是異步編程終級(jí)解決方案的 async/await。我第一次看到這組關(guān)鍵字并不是在 JavaSc...

    tracymac7 評(píng)論0 收藏0
  • 前端校招準(zhǔn)備系列--js中的setTimeout到底什么?

    摘要:瀏覽器是多進(jìn)程的,而瀏覽器的內(nèi)核渲染進(jìn)程是多線程的。如果已經(jīng)將回調(diào)函數(shù)放進(jìn)任務(wù)隊(duì)列,但是主線程正在執(zhí)行一個(gè)非常耗時(shí)的任務(wù),當(dāng)這個(gè)任務(wù)執(zhí)行完畢后,主線程去任務(wù)隊(duì)列中取任務(wù),這個(gè)時(shí)候,就會(huì)出現(xiàn)連續(xù)執(zhí)行的情況,也就是說相當(dāng)于失效了。 前言 ??在刷筆試題的時(shí)候,經(jīng)常會(huì)碰到setTimeout的問題,只知道這個(gè)是設(shè)置定時(shí)器;但是考察的重點(diǎn)一般是在一個(gè)方法中包含了定時(shí)器,定時(shí)器中的打印和方法中打...

    Godtoy 評(píng)論0 收藏0
  • [譯] 深入理解 Promise 五部曲:1. 異步問題

    摘要:當(dāng)引擎開始執(zhí)行一個(gè)函數(shù)比如回調(diào)函數(shù)時(shí),它就會(huì)把這個(gè)函數(shù)執(zhí)行完,也就是說只有執(zhí)行完這段代碼才會(huì)繼續(xù)執(zhí)行后面的代碼。當(dāng)條件允許時(shí),回調(diào)函數(shù)就會(huì)被運(yùn)行?,F(xiàn)在,返回去執(zhí)行注冊(cè)的那個(gè)回調(diào)函數(shù)。 原文地址:http://blog.getify.com/promis... 在微博上看到有人分享LabJS作者寫的關(guān)于Promise的博客,看了下覺得寫得很好,分五個(gè)部分講解了Promise的來龍去脈。從...

    CHENGKANG 評(píng)論0 收藏0
  • JavaScript Promise 告別異步亂嵌套

    摘要:回調(diào)函數(shù)少了還好,一旦多了起來而且必須講究執(zhí)行順序的話,回調(diào)函數(shù)開始嵌套,那代碼的惡心程度是相當(dāng)不符合常人的線性思維的。 什么是Promise? 在說Promise之前, 不得不說一下,JavaScript的嵌套的回調(diào)函數(shù) 在JavaScript語言中, 無論是寫瀏覽器端的各種事件回調(diào)、ajax回調(diào),還是寫Node.js上的業(yè)務(wù)邏輯,不得不面對(duì)的問題就是各種回調(diào)函數(shù)?;卣{(diào)函數(shù)少了還好,...

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

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

0條評(píng)論

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