摘要:三是控制反轉(zhuǎn)控制權(quán)在其他人的代碼上,假如異步函數(shù)是別人提供的庫(kù),我們把回調(diào)函數(shù)傳進(jìn)去,我們并不能知道異步函數(shù)在調(diào)用回調(diào)函數(shù)之外做了什么事情。錯(cuò)誤捕捉相比回調(diào)函數(shù)的錯(cuò)誤無(wú)法在外部捕捉的問(wèn)題,能夠?yàn)橐贿B串的異步調(diào)用提供錯(cuò)誤處理。
前言
《JS異步編程之 callback》一文我們了解了“JS 是基于單線程事件循環(huán)”的概念構(gòu)建的,回調(diào)函數(shù)不會(huì)立即執(zhí)行,由事件輪詢(xún)?nèi)z測(cè)事件是否執(zhí)行完畢,當(dāng)執(zhí)行完有結(jié)果后,將結(jié)果放入回調(diào)函數(shù)的參數(shù)中,然后將回調(diào)函數(shù)添加到事件隊(duì)列中等待被執(zhí)行。
同時(shí)也講了回調(diào)函數(shù)的問(wèn)題:
一是“回調(diào)地獄”,因?yàn)楫惒交卣{(diào)函數(shù)的特點(diǎn):回調(diào)函數(shù)是作為異步函數(shù)的參數(shù),一層一層嵌套,當(dāng)嵌套過(guò)多,將使代碼邏輯變得混亂,也無(wú)法做好錯(cuò)誤捕捉和處理(只能在回調(diào)函數(shù)內(nèi)部 try catch)。
二是回調(diào)的執(zhí)行方式不符合自然語(yǔ)言的線性思維方式,不容易被理解。
三是控制反轉(zhuǎn)(控制權(quán)在其他人的代碼上),假如異步函數(shù)是別人提供的庫(kù),我們把回調(diào)函數(shù)傳進(jìn)去,我們并不能知道異步函數(shù)在調(diào)用回調(diào)函數(shù)之外做了什么事情。
func1(() => { func2(() => { func3(() => { func4(() => { try { ... } catch (err){ ... } }) }); }); });一、Promise 原理
首先,Promise 中文翻譯為“承諾”, 是 JavaScript 的一種對(duì)象,表示承諾終將返回一個(gè)結(jié)果,無(wú)論成功還是失敗。
Promise 有三個(gè)狀態(tài):等待中(pending),完成(fullfilled),失?。╮ejected), Promise 的設(shè)計(jì)具有原子性,狀態(tài)一旦從 pending 狀態(tài)轉(zhuǎn)換為 fullfilled 狀態(tài)或者 rejected 狀態(tài)后,將不能被改變。
var promise1 = new Promise((resolve, reject) => { console.log("Promise 構(gòu)造器會(huì)立即執(zhí)行"); setTimeout(function (){ if(true) { resolve("完成"); } else { reject("失敗"); } }, 1000); }) promise1 .then((result) => { // do something console.log(result); return 1 // return Promise.resolve(1); // 返回一個(gè)決議為成功的 promise 實(shí)例 // return Promise.reject("error"); // 返回一個(gè)決議為拒絕的 Promise 實(shí)例 }) .then((result) => { // .then() 方法會(huì)返回一個(gè) promise, 完成調(diào)用的參數(shù)為前一個(gè) promise 的返回值或者決議值。 // do other things console.log(result); throw new Error("錯(cuò)誤") // 拋出錯(cuò)誤是隱式拒絕 }) .catch((error) => { // 捕捉錯(cuò)誤 console.log(error) }) .then(() => { // 還能繼續(xù)執(zhí)行! }) .finally(() => { // always do somethings console.log("finally!") })二、Promise 的優(yōu)勢(shì)
鏈?zhǔn)秸{(diào)用
Promise 使用 then 方法后還會(huì)返回一個(gè)新的 Promise 對(duì)象,便于我們傳遞狀態(tài)數(shù)據(jù),同時(shí)鏈?zhǔn)綄?xiě)法接近于同步寫(xiě)法,更符合線性思維。
錯(cuò)誤捕捉
相比回調(diào)函數(shù)的錯(cuò)誤無(wú)法在外部捕捉的問(wèn)題,Promise 能夠?yàn)橐贿B串的異步調(diào)用提供錯(cuò)誤處理。
控制反轉(zhuǎn)再反轉(zhuǎn)
由于第三方提供的異步函數(shù),無(wú)法保證回調(diào)函數(shù)如何被執(zhí)行,但是 Promise 的特點(diǎn),能夠保證異步函數(shù)只能被 resolve 一次,以及始終以異步的形式執(zhí)行代碼。
可以利用 Promise.all 和 Promise.race 來(lái)解決 Promise 始終未決議和并行 Promise 嵌套的問(wèn)題
三、Promise 的不足每個(gè) .then() 都是一個(gè)獨(dú)立的作用域
加入有很多個(gè) .then() 方法,就會(huì)創(chuàng)建很多個(gè)獨(dú)立的作用域,那么將只能通過(guò)外面包裹一層函數(shù)作用域的閉包來(lái)共享狀態(tài)數(shù)據(jù)
無(wú)法取消單個(gè) .then()
當(dāng) Promise 鏈中任意一個(gè) .then() 方法中有語(yǔ)句執(zhí)行錯(cuò)誤后,盡管經(jīng)過(guò) catch 方法的錯(cuò)誤處理,還是并不會(huì)中斷整個(gè) Promise 鏈的執(zhí)行。
無(wú)法得知進(jìn)度
由于 Promise 只能從 pending 到 fullfilled 或 rejected 狀態(tài),無(wú)法得知 pending 階段的進(jìn)度。
四、Promise 應(yīng)用// Promise 封裝 ajax function fetch(method, url, data){ return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest(); var method = method || "GET"; var data = data || null; xhr.open(method, url, true); xhr.onreadystatechange = function() { if(xhr.status === 200 && xhr.readyState === 4){ resolve(xhr.responseText); } else { reject(xhr.responseText); } } xhr.send(data); }) } // 使用 fetch("GET", "/some/url.json", null) .then(result => { console.log(result); }) // 封裝 nodejs error first 風(fēng)格回調(diào) function readFile(url) { return new Promise((resolve, reject) => { fs.readFile(url,"utf8", (err, data) => { if(err) { reject(err); return; } resolve(data) }) }) }五、總結(jié)
Promise 是 ES6 提出的簡(jiǎn)化異步流程控制的新規(guī)范,強(qiáng)調(diào)異步任務(wù)的完成狀態(tài)且具有原子性,這使得我們的代碼更容易追蹤和維護(hù)。Promise 在事件輪詢(xún)中屬于異步事件隊(duì)列中的微任務(wù),而微任務(wù)總是一次性全部執(zhí)行,而宏任務(wù)是每輪輪詢(xún)執(zhí)行一個(gè),此節(jié)內(nèi)容參考我之前的文章《JS專(zhuān)題之事件循環(huán)》。
2019/02/24 @Manncoffee
歡迎關(guān)注我的個(gè)人公眾號(hào)“謝南波”,專(zhuān)注分享原創(chuàng)文章。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/102060.html
摘要:從最開(kāi)始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。異步編程入門(mén)的全稱(chēng)是前端經(jīng)典面試題從輸入到頁(yè)面加載發(fā)生了什么這是一篇開(kāi)發(fā)的科普類(lèi)文章,涉及到優(yōu)化等多個(gè)方面。 TypeScript 入門(mén)教程 從 JavaScript 程序員的角度總結(jié)思考,循序漸進(jìn)的理解 TypeScript。 網(wǎng)絡(luò)基礎(chǔ)知識(shí)之 HTTP 協(xié)議 詳細(xì)介紹 HTT...
摘要:因?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是單線程的,...
摘要:異步編程解決方案筆記最近讀了樸靈老師的深入淺出中異步編程一章,并參考了一些有趣的文章。另外回調(diào)函數(shù)中的也失去了意義,這會(huì)使我們的程序必須依賴(lài)于副作用。 JavaScript 異步編程解決方案筆記 最近讀了樸靈老師的《深入淺出NodeJS》中《異步編程》一章,并參考了一些有趣的文章。在此做個(gè)筆記,記錄并鞏固學(xué)到的知識(shí)。 JavaScript異步編程的兩個(gè)核心難點(diǎn) 異步I/O、事件驅(qū)動(dòng)使得...
摘要:的翻譯文檔由的維護(hù)很多人說(shuō),阮老師已經(jīng)有一本關(guān)于的書(shū)了入門(mén),覺(jué)得看看這本書(shū)就足夠了。前端的異步解決方案之和異步編程模式在前端開(kāi)發(fā)過(guò)程中,顯得越來(lái)越重要。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(shū)(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會(huì)promise...... 本書(shū)的目的是以目前還在制定中的ECMASc...
摘要:函數(shù)會(huì)在之后的某個(gè)時(shí)刻觸發(fā)事件定時(shí)器。事件循環(huán)中的這樣一次遍歷被稱(chēng)為一個(gè)。執(zhí)行完畢并出棧。當(dāng)定時(shí)器過(guò)期,宿主環(huán)境會(huì)把回調(diào)函數(shù)添加至事件循環(huán)隊(duì)列中,然后,在未來(lái)的某個(gè)取出并執(zhí)行該事件。 原文請(qǐng)查閱這里,略有改動(dòng)。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原理的第四章。 現(xiàn)在,我們將會(huì)通過(guò)回顧單線程環(huán)境下編程的弊端及如何克服這些困難以創(chuàng)建令人驚嘆...
閱讀 2666·2023-04-25 15:22
閱讀 2837·2021-10-11 10:58
閱讀 1057·2021-08-30 09:48
閱讀 1864·2019-08-30 15:56
閱讀 1740·2019-08-30 15:53
閱讀 1105·2019-08-29 11:16
閱讀 1058·2019-08-23 18:34
閱讀 1649·2019-08-23 18:12