以下文章來(lái)源于程序人生 ,作者馬超
程序人生
笑談開(kāi)發(fā)軼事,品味程序人生。
點(diǎn)擊上方“Python大本營(yíng)”,選擇“置頂公眾號(hào)”Python大本營(yíng) IT人的職業(yè)提升平臺(tái)
4月25日,一個(gè)體量很小的 JavaScript 庫(kù)is-promise 進(jìn)行了更新。由于最新版本沒(méi)有遵循正確的 ES 模塊標(biāo)準(zhǔn),使得超過(guò)300萬(wàn)個(gè)引用了is-promise的前端項(xiàng)目均出現(xiàn)了問(wèn)題,這個(gè)問(wèn)題甚至讓整個(gè) JavaScript 生態(tài)系統(tǒng)陷入了混亂。由于前端項(xiàng)目的構(gòu)造方式與中后臺(tái)項(xiàng)目的機(jī)制不同,這種由小型 JavaScript 項(xiàng)目引起廣泛?jiǎn)栴}的情況已經(jīng)不是第一次發(fā)生了。這次的問(wèn)題并沒(méi)有導(dǎo)致現(xiàn)有 JS 項(xiàng)目崩潰,主要問(wèn)題是無(wú)法編譯新版本。當(dāng)筆者看到這個(gè)新聞,心中不由得一顫,因?yàn)樗就秸览蠋熒耙恢眾^斗的前端技術(shù)領(lǐng)域,當(dāng)我來(lái)寫這篇文章時(shí),執(zhí)筆當(dāng)哭,緬懷舊人。筆者和司徒結(jié)識(shí)于CSDN,記得是去年6月,當(dāng)時(shí)我看到一篇博文《前端開(kāi)發(fā) 20 年變遷史》,心中不由贊嘆,竟有人能將前端技術(shù)上升到哲學(xué)高度來(lái)進(jìn)行闡釋,于是千方百計(jì)地找到了司徒的微信加為好友,和司徒聊天中,明顯能感受到他對(duì)于前端技術(shù)的理解深度和積極熱情。誰(shuí)知天有不測(cè)風(fēng)云,司徒年紀(jì)輕輕竟然溘然長(zhǎng)逝,在此筆者也提示各位讀者朋友們保重身份,切莫透支健康。下面筆者幫助大家解讀一下這則新聞背后的技術(shù)細(xì)節(jié)。由于前端并不是筆者的領(lǐng)域,如有錯(cuò)漏還請(qǐng)各位指正。因?yàn)楣P者對(duì)于JavaScript也不是特別了解,在初步學(xué)習(xí)后我看到了阻塞代碼、非阻塞代碼、事件驅(qū)動(dòng)設(shè)計(jì)模式、事件生命周期、函數(shù)堆棧、事件隊(duì)列等概念,以及polyfill、babel、angular、reactJS、Vue.JS 等框架。JavaScript是單線程執(zhí)行代碼,但是由于具備非阻塞和回調(diào)機(jī)制,JavaScript也可以實(shí)現(xiàn)異步功能。于是有了Promise機(jī)制。根據(jù)MDN上對(duì)于Promise機(jī)制的描述(https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise):Promise對(duì)象是一個(gè)代理對(duì)象(代理一個(gè)值),被代理的值在Promise對(duì)象創(chuàng)建時(shí)可能是未知的。它允許你為異步操作的成功和失敗分別綁定相應(yīng)的處理方法(handlers)。這讓異步方法可以像同步方法那樣返回值,但并不是立即返回最終執(zhí)行結(jié)果,而是一個(gè)能代表未來(lái)出現(xiàn)的結(jié)果的promise對(duì)象。//創(chuàng)建一個(gè)Promise對(duì)象,定義resolve方法,在3000ms后執(zhí)行。
const promise1 = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('promise');
}, 3000);
});
//非阻塞執(zhí)行promise1,在promise完成后此方法會(huì)被執(zhí)行。
promise1.then(function(value) {
console.log(value);
// 3s后會(huì)輸出promise
});
console.log(promise1);
//直接輸出 [object Promise]
綜上筆者認(rèn)為可以將Promise理解成Java中的Callback,用以幫助JavaScript實(shí)現(xiàn)異步功能。本次出現(xiàn)問(wèn)題的is-promise包,作用是測(cè)試一個(gè)JavaScript對(duì)象是否為Promise的。is-promise包的代碼其實(shí)非常短,其主要的功能實(shí)現(xiàn)代碼只有兩行而已。前端開(kāi)發(fā)人員在引入is-promise包之后,就能在自己的項(xiàng)目中引用它,而且is-promise包是基于MIT協(xié)議的,因此引用該項(xiàng)目,也不必須要求開(kāi)源。雖然只有兩行代碼,但is-promise 庫(kù)卻是當(dāng)今最受歡迎的 JavaScript 軟件包之一。據(jù)不完全統(tǒng)計(jì),is-promise是700余個(gè)知名的JavaScript 庫(kù)的依賴項(xiàng),其影響項(xiàng)目數(shù)量至少超過(guò)300萬(wàn),范圍涵蓋至封閉源 JavaScript 代碼庫(kù)和 JavaScript 生態(tài)系統(tǒng)中一些最大的項(xiàng)目。其中包括有:Facebook 的 Create React App(用于創(chuàng)建 React 應(yīng)用程序的標(biāo)準(zhǔn)模板)、谷歌的 Angular.js 框架、谷歌的 Firebasse-tools、亞馬遜的 AWS Serverless CLI、Nuxt.js 和 AVA 等。引發(fā)問(wèn)題的ES 模塊標(biāo)準(zhǔn)is-promise 庫(kù)之所以引發(fā)問(wèn)題,關(guān)鍵在于沒(méi)有遵循正確的ES模塊標(biāo)準(zhǔn),而提到ES模塊標(biāo)準(zhǔn)(EMS),我們還要從最基本的概念聊起。我們知道JavaScript是一門動(dòng)態(tài)的腳本化語(yǔ)言,它讓前端頁(yè)面的開(kāi)發(fā)變得非常簡(jiǎn)單。JavaScript的編程范式抽象成維護(hù)變量、賦值和計(jì)算操作。大量的代碼用于操作變量,開(kāi)發(fā)者需要懂得如何去組織和維護(hù)這些變量。JavaScript 提供了一種方式,即函數(shù)作用域。在一個(gè)函數(shù)內(nèi)只需要考慮這個(gè)函數(shù)的變量問(wèn)題,不必去擔(dān)心其他函數(shù)會(huì)操作這些變量。隨之帶來(lái)的問(wèn)題是變量無(wú)法共享,無(wú)法在不同的函數(shù)之間相互共享變量。如果想要在作用域外共享變量,只能通過(guò)外層作用域,或者全局作用域。ES模塊標(biāo)準(zhǔn)是提供了更好的方式來(lái)組織變量和函數(shù),把相關(guān)的變量和函數(shù)組織到一起。具體就是將這些函數(shù)和變量放到一個(gè)模塊作用域內(nèi),實(shí)現(xiàn)在模塊間共享變量。與函數(shù)作用域不同的是,模塊內(nèi)部的變量實(shí)現(xiàn)了在其他模塊內(nèi)共享。還可指定哪些變量、類或者函數(shù)可以共享。在其他模塊中共享,被稱為 export。這就出現(xiàn)了模塊間的依賴,這是一種很明確的關(guān)系,當(dāng)移除一個(gè)模塊時(shí)可以準(zhǔn)確地知道哪些模塊會(huì)出錯(cuò)。一旦有了模塊間導(dǎo)出和引用變量的能力,我們就可以將代碼打成小包。然后就可以像樂(lè)高玩具那樣組合,再組合。使用小模塊就可以創(chuàng)建出各類應(yīng)用。在使用模塊的時(shí)候,其實(shí)就是在做一個(gè)依賴關(guān)系圖。ESM的模塊包括三個(gè)過(guò)程:1、構(gòu)建:下載,解析,然后把文件解析為模塊記錄;2、實(shí)例化:為模塊分內(nèi)存空間(此時(shí)還沒(méi)賦值),然后依照導(dǎo)入,導(dǎo)出語(yǔ)句把模塊指向內(nèi)存地址,這個(gè)過(guò)程叫鏈接;3、運(yùn)行(求值):運(yùn)行代碼的時(shí)候,才會(huì)給內(nèi)存空間填充真實(shí)的值。EMS則通過(guò)一系列的標(biāo)準(zhǔn)來(lái)確保相關(guān)代碼可以實(shí)現(xiàn)上述模塊化的功能。is-promise v.2.2.0 版本卻未遵循正確的 ES 模塊標(biāo)準(zhǔn)。因此在其更新發(fā)布后,引用了is-promise在各個(gè)項(xiàng)目都在的構(gòu)建鏈時(shí)出現(xiàn)了問(wèn)題。總結(jié)一下本文內(nèi)容,Promise是Javascript中實(shí)現(xiàn)異步功能的重要機(jī)制,is-promise又是目前流行度最高的promise對(duì)象檢測(cè)工具,而由于is-promise沒(méi)有遵循正確的ES模塊標(biāo)準(zhǔn),使得其它引用了is-promise包的程序出現(xiàn)了問(wèn)題。最后引用司徒正美老師在《前端開(kāi)發(fā) 20 年變遷史》的話來(lái)做結(jié)束:“當(dāng)初JavaScript被誤解為最糟糕的語(yǔ)言,時(shí)至今日它是最流行的語(yǔ)言,GitHub 60%的項(xiàng)目都是與JavaScript有關(guān)……任何可以使用JavaScript來(lái)編寫的應(yīng)用,最終會(huì)由JavaScript編寫。”愿前端開(kāi)發(fā)之路越來(lái)越好!npm地址:https://www.npmjs.com/package/p-is-promiseGithub地址:https://github.com/sindresorhus/p-is-promise本文福利來(lái)啦,趕快來(lái)免費(fèi)領(lǐng)取硬核學(xué)習(xí)資料吧??:
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)
點(diǎn)擊舉報(bào)。