Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 真实的国产乱xxxx在线,国产成人精品午夜在线播放 ,99久久精品免费观看国产

          整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          前端代碼Review,一次性掰扯明白!

          前端代碼Review,一次性掰扯明白!

          要Review的指標(biāo)

          前端代碼Review主要關(guān)注以下幾個(gè)方面:

          1、代碼質(zhì)量:代碼是否簡(jiǎn)潔、易讀、易維護(hù)。是否遵循了一致的編碼風(fēng)格和規(guī)范,例如ESLint、Prettier等。
          2、功能實(shí)現(xiàn):代碼是否實(shí)現(xiàn)了預(yù)期的功能,是否有潛在的bug或邏輯錯(cuò)誤。
          3、性能優(yōu)化:代碼是否進(jìn)行了必要的性能優(yōu)化,例如避免不必要的渲染、使用了合適的數(shù)據(jù)結(jié)構(gòu)和算法等。
          4、安全性:代碼是否存在可能的安全風(fēng)險(xiǎn),例如XSS攻擊、CSRF攻擊等。

          5、可測(cè)試性:代碼是否易于測(cè)試,是否有單元測(cè)試和集成測(cè)試。
          6、可讀性:代碼是否易于理解,是否有足夠的注釋和文檔。
          7、可復(fù)用性:代碼是否有高度的模塊化和復(fù)用性。
          8、兼容性:代碼是否兼容不同的瀏覽器和設(shè)備。

          助記:功性讀復(fù)全兼測(cè)

          功能Review

          • 無(wú)需人為檢測(cè),但注釋要寫(xiě)明白,TS類(lèi)型要寫(xiě)清楚,讓用的人如沐春風(fēng);
          • 該匹配單元測(cè)試的建議配套單元測(cè)試,不落人以口實(shí)~

          性能Review

          前端代碼中一些典型的、肉眼可見(jiàn)的需要性能優(yōu)化的地方包括:

          1、過(guò)度渲染:如果你的應(yīng)用在沒(méi)有必要的情況下進(jìn)行了過(guò)多的渲染,這可能會(huì)導(dǎo)致性能問(wèn)題。例如,在React中,如果你的組件在props沒(méi)有改變的情況下進(jìn)行了重新渲染,那么你可能需要使用shouldComponentUpdate/SCU或React.PureComponent或useEffect來(lái)避免不必要的渲染。
          2、大量DOM操作:頻繁的DOM操作是非常耗費(fèi)性能的。如果你的代碼中有大量的DOM操作,你可能需要考慮使用虛擬DOM或其他優(yōu)化技術(shù)(例如DocumentFragment)。
          3、大量的網(wǎng)絡(luò)請(qǐng)求:如果你的應(yīng)用發(fā)送了大量的網(wǎng)絡(luò)請(qǐng)求,這可能會(huì)導(dǎo)致性能問(wèn)題。你可能需要考慮使用緩存、預(yù)加載、懶加載等技術(shù)來(lái)減少網(wǎng)絡(luò)請(qǐng)求。
          4、大型JavaScript文件:如果你的JavaScript文件過(guò)大,這可能會(huì)導(dǎo)致加載和解析時(shí)間過(guò)長(zhǎng)。你可能需要考慮使用代碼分割、懶加載等技術(shù)來(lái)減小文件大小。
          5、未優(yōu)化的圖片和媒體文件:如果你的網(wǎng)站使用了大量的未優(yōu)化的圖片和媒體文件,這可能會(huì)導(dǎo)致加載時(shí)間過(guò)長(zhǎng)。你可能需要考慮使用圖片壓縮、適當(dāng)?shù)奈募袷健DN等技術(shù)來(lái)優(yōu)化你的媒體文件。
          6、阻塞渲染的CSS和JavaScript:如果你的CSS和JavaScript阻塞了頁(yè)面的渲染,這可能會(huì)導(dǎo)致用戶體驗(yàn)不佳。你可能需要考慮使用非阻塞的加載技術(shù),如異步加載、延遲加載等。

          非阻塞加載CSS和JS

          阻塞渲染的CSS和JavaScript是一個(gè)常見(jiàn)的前端性能優(yōu)化問(wèn)題。當(dāng)瀏覽器加載網(wǎng)頁(yè)時(shí),它會(huì)按照HTML文檔的順序解析每個(gè)元素。當(dāng)遇到<link>或<script>標(biāo)簽時(shí),瀏覽器會(huì)停止HTML解析,去下載和執(zhí)行CSS或JavaScript文件,這就是所謂的“阻塞渲染”

          以下是一些優(yōu)化阻塞渲染的CSS和JavaScript的策略:


          1、異步加載JavaScript:使用async屬性可以使瀏覽器異步加載JavaScript,即在下載JavaScript文件的同時(shí),瀏覽器可以繼續(xù)解析HTML。但是,這可能會(huì)導(dǎo)致JavaScript在DOM還未完全解析時(shí)就開(kāi)始執(zhí)行,因此只適用于那些不依賴DOM的JavaScript文件

          2、延遲加載JavaScript:使用defer屬性可以使瀏覽器延遲執(zhí)行JavaScript,即在DOM解析完畢后,再執(zhí)行JavaScript。這適用于那些依賴DOM的JavaScript文件

          3、內(nèi)聯(lián)關(guān)鍵CSS:將關(guān)鍵的CSS(即渲染首屏內(nèi)容所需的CSS)內(nèi)聯(lián)到HTML中,可以避免瀏覽器等待CSS文件的下載和解析。但是,這可能會(huì)增加HTML文件的大小,因此只適用于小量的CSS

          4、媒體查詢:使用媒體查詢可以讓瀏覽器只下載適用于當(dāng)前設(shè)備的CSS,從而減少不必要的下載;本質(zhì)是一種CSS的按需加載技術(shù)

          以上就是優(yōu)化阻塞渲染的CSS和JavaScript的一些策略。

          可讀性Review

          關(guān)注一下以下要點(diǎn):

          • 變量、函數(shù)、類(lèi)、文件和文件夾的語(yǔ)義化命名
          • 注釋
          • 文檔
          • TS類(lèi)型聲明

          復(fù)用性Review

          正在review的這段代碼可復(fù)用性如何,高的話是否可以:

          • 封裝為函數(shù)
          • 封裝為類(lèi)
          • 封裝為指令
          • 封裝為hook
          • 封裝為組件
          • 封裝為模塊

          安全性Review

          在前端代碼的安全性Review中,主要關(guān)注以下幾個(gè)方面:

          1、跨站腳本攻擊(XSS):檢查代碼中是否正確地對(duì)用戶輸入進(jìn)行了轉(zhuǎn)義,以防止插入惡意的JavaScript代碼。例如,當(dāng)使用React時(shí),它默認(rèn)會(huì)轉(zhuǎn)義所有的用戶輸入,但如果你使用dangerouslySetInnerHTML(或Vue中的v-html),則需要特別小心。
          2、跨站請(qǐng)求偽造(CSRF):檢查是否在所有的POST請(qǐng)求中使用了CSRF令牌,以防止攻擊者偽造用戶的請(qǐng)求。
          3、點(diǎn)擊劫持:檢查是否使用了適當(dāng)?shù)腍TTP頭,如X-Frame-Options,來(lái)防止點(diǎn)擊劫持攻擊。
          4、內(nèi)容篡改:檢查是否所有的HTTP請(qǐng)求都使用了HTTPS,以防止混合內(nèi)容問(wèn)題,這可能會(huì)導(dǎo)致用戶的數(shù)據(jù)被竊取(傳輸過(guò)程中被抓包)。
          5、輸入驗(yàn)證:檢查是否在客戶端和服務(wù)器端都進(jìn)行了輸入驗(yàn)證,以防止注入攻擊,圖形或字符驗(yàn)證碼、短信驗(yàn)證、CSRF-token等的本質(zhì)都是加入隨機(jī)真人校驗(yàn)機(jī)制,狠重要!
          6、敏感信息泄露:檢查代碼中是否有可能泄露敏感信息的地方,如在URL、錯(cuò)誤消息或日志中包含敏感信息。
          7、依賴的安全性:檢查所有的第三方依賴是否都是最新的,是否有已知的安全漏洞

          點(diǎn)擊劫持

          X-Frame-Options 是一個(gè)HTTP響應(yīng)頭,用于控制網(wǎng)頁(yè)是否可以被其他網(wǎng)頁(yè)通過(guò)、或等元素嵌入。這個(gè)響應(yīng)頭的主要目的是為了防止點(diǎn)擊劫持/Clickjacking攻擊。

          X-Frame-Options有三個(gè)可能的值:

          1. DENY:此頁(yè)面不能被嵌入到任何其他頁(yè)面中。

          2. SAMEORIGIN:只有同源的頁(yè)面(即,URL的協(xié)議、域名和端口都相同)才能嵌入此頁(yè)面。

          3. ALLOW-FROM uri:只有指定的頁(yè)面可以嵌入此頁(yè)面。但是,這個(gè)值已經(jīng)被廢棄,不再被大多數(shù)現(xiàn)代瀏覽器支持。

          如果沒(méi)有設(shè)置X-Frame-Options頭,或者設(shè)置的值不是上述三個(gè)值之一,那么任何頁(yè)面都可以嵌入此頁(yè)面。因此,為了防止點(diǎn)擊劫持攻擊,建議總是設(shè)置X-Frame-Options頭

          兼容性Review

          在前端代碼的兼容性Review中,主要關(guān)注以下幾個(gè)方面:

          1、瀏覽器兼容性:檢查代碼是否能在所有支持的瀏覽器中正常工作。這包括檢查是否使用了某些瀏覽器可能不支持的JavaScript特性或CSS屬性,以及是否正確地使用了polyfill和前綴。
          2、設(shè)備兼容性:檢查代碼是否能在所有支持的設(shè)備中正常工作,包括不同的操作系統(tǒng)、屏幕大小和分辨率。
          3、響應(yīng)式設(shè)計(jì):檢查代碼是否適應(yīng)了不同的屏幕大小,包括手機(jī)、平板和桌面。
          4、無(wú)障礙性:檢查代碼是否遵循了無(wú)障礙性標(biāo)準(zhǔn),如WAI-ARIA,以確保所有用戶,包括那些使用輔助技術(shù)的用戶,都能使用你的應(yīng)用。
          5、國(guó)際化和本地化:檢查代碼是否支持多種語(yǔ)言和地區(qū),包括正確地使用了日期、時(shí)間和數(shù)字的格式。
          6、性能:檢查代碼在低性能的設(shè)備或網(wǎng)絡(luò)環(huán)境下是否還能正常工作。

          即充分考慮不同瀏覽器、不同設(shè)備、不同屏幕、不同國(guó)家、不同人群

          什么是polyfill

          • Polyfill是一段代碼(通常是JavaScript),用于為舊的或不支持某些特性的瀏覽器提供這些特性的實(shí)現(xiàn)。Polyfill的目的是讓開(kāi)發(fā)者能夠使用新的、更高級(jí)的API,而不用擔(dān)心兼容性問(wèn)題。
          • 例如,Array.prototype.includes是一個(gè)新的JavaScript特性,用于檢查數(shù)組中是否包含某個(gè)元素。但是,這個(gè)特性在IE瀏覽器中是不支持的。為了在IE中也能使用這個(gè)特性,我們可以使用一個(gè)polyfill,如下:

          • 這段代碼首先檢查Array.prototype.includes是否存在。如果不存在(即,瀏覽器不支持這個(gè)特性),那么就給Array.prototype添加一個(gè)includes方法,這個(gè)方法的行為和原生的includes方法一樣。
          • 在實(shí)際開(kāi)發(fā)中,我們通常不會(huì)自己寫(xiě)polyfill,而是使用已經(jīng)存在的polyfill庫(kù),如core-js或polyfill.io。
          • 需要注意的是,雖然polyfill可以讓我們?cè)谂f瀏覽器中使用新特性,但是它也有一些缺點(diǎn)。首先,polyfill會(huì)增加代碼的大小,可能會(huì)影響網(wǎng)頁(yè)的加載速度。其次,polyfill可能無(wú)法完全模擬新特性的行為,特別是一些復(fù)雜的或與性能相關(guān)的特性。因此,在使用polyfill時(shí),需要權(quán)衡其利弊。

          配置polyfill

          • 安裝polyfill庫(kù)通常是第一步,但是你可能還需要進(jìn)行一些配置,以確保polyfill能夠在你的代碼中正確地工作。
          • 具體的配置步驟取決于你使用的polyfill庫(kù)和構(gòu)建工具。
          • 以core-js和babel為例,你可以按照以下步驟來(lái)配置polyfill:
          1. 首先,安裝core-js和@babel/preset-env:

          1. 然后,在你的.babelrc文件(或者babel的配置文件)中,添加@babel/preset-env預(yù)設(shè),并設(shè)置useBuiltIns和corejs選項(xiàng):

          • 這里的useBuiltIns選項(xiàng)有兩個(gè)可能的值:"usage"和"entry"。如果設(shè)置為"usage",那么babel會(huì)自動(dòng)檢測(cè)你的代碼中使用了哪些新特性,然后只包含這些特性的polyfill。如果設(shè)置為"entry",那么你需要在你的代碼的入口文件中,手動(dòng)導(dǎo)入所有需要的polyfill:

          以上就是配置polyfill的一個(gè)示例。需要注意的是,這只是一個(gè)基本的配置,實(shí)際的配置可能會(huì)更復(fù)雜,取決于你的具體需求和環(huán)境。

          可測(cè)試性Review

          在前端代碼的可測(cè)試性Review中,主要關(guān)注以下幾個(gè)方面:

          1、單元測(cè)試:檢查代碼是否易于進(jìn)行單元測(cè)試。這包括檢查函數(shù)是否是純函數(shù)(即,相同的輸入總是產(chǎn)生相同的輸出,沒(méi)有副作用),以及是否避免了全局狀態(tài)。

          2、集成測(cè)試:檢查代碼是否易于進(jìn)行集成測(cè)試。這包括檢查組件是否正確地使用了props和state,以及是否避免了直接操作DOM。

          3、端到端測(cè)試:檢查代碼是否易于進(jìn)行端到端測(cè)試。這包括檢查頁(yè)面是否有易于定位的元素(如有特定id或data-test屬性的元素),以及是否有清晰的用戶流程。

          4、測(cè)試覆蓋率:檢查代碼的測(cè)試覆蓋率是否足夠。這包括檢查是否所有的函數(shù)和分支都有對(duì)應(yīng)的測(cè)試。

          5、模擬和打樁:檢查代碼是否易于進(jìn)行模擬和打樁。這包括檢查函數(shù)是否避免了直接調(diào)用復(fù)雜的依賴(如網(wǎng)絡(luò)請(qǐng)求或數(shù)據(jù)庫(kù)操作),以及是否提供了足夠的接口來(lái)替換這些依賴。

          6、錯(cuò)誤處理:檢查代碼是否正確地處理了可能的錯(cuò)誤。這包括檢查是否有錯(cuò)誤處理函數(shù)或catch塊,以及是否有對(duì)應(yīng)的錯(cuò)誤測(cè)試。

          端到端測(cè)試

          • 端到端(End-to-End,E2E)測(cè)試 是一種測(cè)試方法,用于測(cè)試應(yīng)用的整個(gè)工作流程,從用戶界面到數(shù)據(jù)庫(kù),確保所有部分都能正確地協(xié)同工作。
          • 在React應(yīng)用中,我們可以使用Cypress或Puppeteer等工具來(lái)進(jìn)行E2E測(cè)試。以下是一個(gè)使用Cypress進(jìn)行E2E測(cè)試的基本步驟:

          1、安裝Cypress:首先,你需要在你的項(xiàng)目中安裝Cypress。你可以使用npm或yarn來(lái)安裝:

          2、編寫(xiě)測(cè)試:然后,你可以在cypress/integration目錄下編寫(xiě)你的E2E測(cè)試。以下是一個(gè)簡(jiǎn)單的測(cè)試示例,它測(cè)試了用戶是否能正確地登錄:

          3、運(yùn)行測(cè)試:最后,你可以使用Cypress的CLI來(lái)運(yùn)行你的測(cè)試:

          這將會(huì)打開(kāi)Cypress的測(cè)試運(yùn)行器,你可以在這里選擇你要運(yùn)行的測(cè)試。

          以上就是在React應(yīng)用中進(jìn)行E2E測(cè)試的基本步驟。需要注意的是,這只是一個(gè)基本的示例,實(shí)際的E2E測(cè)試可能會(huì)更復(fù)雜,包括測(cè)試更多的用戶交互和應(yīng)用狀態(tài)。

          功性讀復(fù)全兼測(cè)! OVER,收工干飯!


          原文鏈接:https://juejin.cn/post/7283748394601840680

          者:magentaqin,騰訊前端開(kāi)發(fā)工程師

          說(shuō)到 Code Review,經(jīng)常有同學(xué)會(huì)問(wèn),究竟從哪些方面下手?除了一些抽象的 Review 原則,有沒(méi)有更細(xì)化的實(shí)施準(zhǔn)則來(lái)指導(dǎo)實(shí)踐?

          PCG 代碼委員會(huì)曾推出過(guò)通道晉級(jí)代碼檢查報(bào)告。筆者打算在這些報(bào)告基礎(chǔ)上,從代碼格式、代碼錯(cuò)誤、代碼習(xí)慣、代碼優(yōu)化四個(gè)角度,并結(jié)合騰訊醫(yī)典前端 Code Review 過(guò)程中遇到的一些 bad case,逐一列出更細(xì)化的實(shí)施準(zhǔn)則。希望對(duì)各位有一定的參考價(jià)值。

          1. 代碼格式

          代碼格式問(wèn)題完全可以通過(guò)自動(dòng)化工具來(lái)解決。 標(biāo)準(zhǔn)的 eslint 規(guī)則( 如Airbnb或公司統(tǒng)一推出的eslint規(guī)則) + husky( 本地pre-commit校驗(yàn) ) + 遠(yuǎn)端 CI 流水線 eslint 校驗(yàn)(開(kāi)啟cache,增量校驗(yàn))就可以解決。

          2. 代碼錯(cuò)誤

          2.1 是否存在會(huì)導(dǎo)致內(nèi)存泄露的代碼

          對(duì)于 SPA 應(yīng)用,用戶無(wú)需刷新瀏覽器,所以要想確保垃圾回收生效,我們需要在組件對(duì)應(yīng)生命周期里做主動(dòng)銷(xiāo)毀。

          1)存在不必要的全局變量且未及時(shí)解除引用

          全局變量,除非你關(guān)閉窗口或者刷新頁(yè)面,才會(huì)被釋放,如果緩存大量數(shù)據(jù),很可能導(dǎo)致內(nèi)存泄露。 比如,我們之前就遇到過(guò)把 IM SDK放在全局window上,但在頁(yè)面卸載時(shí)卻沒(méi)有解除引用。

          mounted () {
            window.im=TWebLive.createIM({ SDKAppID });
          }
          

          解決方案:在頁(yè)面卸載時(shí)解除該全局引用。

          destroyed () {
            window.im=null;
          }
          

          其實(shí)該 im 實(shí)例也不需要掛在window上,直接綁定在vue實(shí)例上即可,組件銷(xiāo)毀時(shí)該實(shí)例也會(huì)銷(xiāo)毀;但沒(méi)有綁定在vue實(shí)例上的一定要主動(dòng)銷(xiāo)毀。

          2)閉包內(nèi)部變量未被銷(xiāo)毀

          來(lái)看一個(gè)容易忽視的閉包引發(fā)內(nèi)存泄漏的例子。 outer函數(shù)內(nèi)部定義了兩個(gè)函數(shù): unused 和 foo。雖然inner函數(shù)中并沒(méi)有使用outer函數(shù)中的變量,但是由于unsed函數(shù)使用了outer函數(shù)的bar變量,bar也不會(huì)被釋放,所以foo相當(dāng)于隱式持有了bar。每次執(zhí)行outer,bar都會(huì)指向上一次的foo;而foo也會(huì)隱式持有bar,這樣的引用關(guān)系導(dǎo)致bar和foo都無(wú)法釋放。

          let foo=null;
          
          function outer() {
            let bar=foo;
            
            // 該函數(shù)歷史原因,調(diào)用方被注釋掉。并無(wú)調(diào)用
            function unused () {
              doSomething();
              console.log(`unused ${bar}`)
            }
            
            // foo賦值
            foo={
              bigData: new Array(10000),
              inner: function () {
                 doSomething();
              }
            }
          }
          
          for (let i=0; i < 1000; i++) {
            outer();
          } 
          

          解決方案:在 outer 執(zhí)行完畢時(shí)手動(dòng)釋放bar。這樣,隱式持有 bar 的 foo 也沒(méi)有其他變量引用,也會(huì)被回收了。

          let foo=null;
          
          function outer() {
            let bar=foo;
            
            // 該函數(shù)歷史原因,調(diào)用方被注釋掉。并無(wú)調(diào)用
            function unused () {
              doSomething();
              console.log(`unused ${bar}`)
            }
            
            // foo賦值
            foo={
              bigData: new Array(10000),
              inner: function () {
                 doSomething();
              }
            }
            
            bar=null; // 手動(dòng)釋放bar
          }
          
          for (let i=0; i < 1000; i++) {
            outer();
          } 
          

          3)定時(shí)器是否及時(shí)清理

          常見(jiàn)的情況是mounted設(shè)置了定時(shí)任務(wù),但卻沒(méi)有及時(shí)清理。

          mounted () {
            this.timer=setTimeout(()=> {
              doSomething();
            }, 300)
          }
          

          參考寫(xiě)法,頁(yè)面銷(xiāo)毀時(shí)需清理定時(shí)器:

          destroyed () {
            if (this.timer) {
              clearTimeout(this.timer)
            }
          }
          

          4)監(jiān)聽(tīng)事件是否有解綁

          window/body 等事件需要解綁:

          mounted() {
            window.addEventListener(‘resize’, this.func)
          }
          beforeDestroy () {
            window.removeEventListener('resize', this.func);
          }
          

          5)第三方庫(kù)的銷(xiāo)毀函數(shù),在頁(yè)面卸載時(shí)也需要調(diào)用,比如EventBus:

          destroyed () {
            this.eventBus.off()
          }
          

          6)v-if 指令導(dǎo)致的內(nèi)存泄露

          拿 vue 官網(wǎng)避免內(nèi)存泄漏 的例子來(lái)看下。

          v-if 指令只是控制虛擬DOM的添加和移除,但是由 Choices.js 添加的 DOM 片段并沒(méi)有被移除。

          <template>
            <div id="app">
              <button v-if="showChoices" @click="hide">Hide</button>
              <button v-if="!showChoices" @click="show">Show</button>
              <div v-if="showChoices">
                <select id="choices-single-default"></select>
              </div>
            </div>
          </template>
          
          <script>
          new Vue({
            el: "#app",
            data: function () {
              return {
                showChoices: true
              }
            },
            mounted: function () {
              this.initializeChoices()
            },
            methods: {
              initializeChoices: function () {
                let list=[]
                for (let i=0; i < 1000; i++) {
                  list.push({
                    label: "Item " + i,
                    value: i
                  })
                }
                new Choices("#choices-single-default", {
                  searchEnabled: true,
                  removeItemButton: true,
                  choices: list
                })
              },
              show: function () {
                this.showChoices=true
                this.$nextTick(()=> {
                  this.initializeChoices()
                })
              },
              hide: function () {
                this.showChoices=false
              }
            }
          })
          </script>
          

          解決辦法是在hide方法里調(diào)用 Choices.js 的API來(lái)清理DOM片段:

          hide: function() {
            this.choicesSelect.destroy();
          }
          

          以下是優(yōu)化前、后的 JS Heap 對(duì)比圖:

          2.2 異步操作是否有異常處理

          異步操作拿接口請(qǐng)求來(lái)說(shuō),大家都知道的是,使用 promise 時(shí)要有.catch 處理。但使用 async/await 時(shí),有.catch 處理的,也有try...catch處理的使用方法。這里推薦使用.catch。原因在于:

          • 可以控制接口請(qǐng)求出錯(cuò)后,是否要阻塞后續(xù)業(yè)務(wù)邏輯執(zhí)行
          • .catch里的 error 能明確知道是接口請(qǐng)求導(dǎo)致的錯(cuò)誤,而不需要再對(duì) error 進(jìn)行分類(lèi)判斷,是接口200返回后的業(yè)務(wù)邏輯處理報(bào)錯(cuò)還是接口報(bào)錯(cuò)。
          // CASE 1: 接口報(bào)錯(cuò),阻塞業(yè)務(wù)邏輯執(zhí)行
          async fetchList() {
            const res=await someApi().catch(error=> {
            // error處理邏輯
            })
            if (res) {
              doA();
            }
           }
           
           // CASE 2: 接口報(bào)錯(cuò),不阻塞業(yè)務(wù)邏輯執(zhí)行
           async fetchList() {
            const res=await someApi().catch(error=> {
            // error處理邏輯
            })
            doA();
           }
           
           // CASE 3:使用try...catch的情況
           async fetchList() {
            try {
            const res=await someApi()
               doA(); 
            } catch (error) {
              // 接口請(qǐng)求出錯(cuò) + 接口響應(yīng)成功后業(yè)務(wù)邏輯處理出錯(cuò)都會(huì)進(jìn)入catch block。需要進(jìn)一步區(qū)分錯(cuò)誤類(lèi)型 
              if (error.bizcode !==0 || error.retcode !==0) {
                reportApiError(error)
              } else {
                reportBusinessError(error)
              }
            }
           }
          

          2.3 取值時(shí)是否進(jìn)行了空判斷、調(diào)用函數(shù)時(shí)是否進(jìn)行了類(lèi)型判斷**

          拿醫(yī)典3月中下旬的錯(cuò)誤日志來(lái)說(shuō),這類(lèi)錯(cuò)誤在錯(cuò)誤日志中占了1/3。


          如果項(xiàng)目里已經(jīng)全量使用了Typescript,這類(lèi)錯(cuò)誤應(yīng)該都可以避免。 但如果項(xiàng)目里還存在 js 代碼,可以使用lodash.get來(lái)做空判斷,在調(diào)用函數(shù)之前要對(duì)函數(shù)做類(lèi)型判斷。

          2.4 存在無(wú)意義的 if else代碼塊或考慮漏的條件

          無(wú)意義的if else代碼塊,指的不僅是空的if else 代碼塊,還有只寫(xiě)了console.log 的情況。 另外,也存在條件判斷過(guò)于復(fù)雜,else情況考慮不全,導(dǎo)致邏輯沒(méi)有正常處理的情況。

          //  else 代碼塊里只寫(xiě)了console.log 
          if (a) {
          } else {
            console.log('something')
          }
          
          // 條件判斷過(guò)于復(fù)雜,else情況考慮不全,導(dǎo)致邏輯不能正常處理
          if ((a && (b || c)) || d || (e && (f || g))) {
          } else {
            doSomething()
          }
          

          解決辦法: 開(kāi)啟eslint no-empty 規(guī)則,不允許有空的block。但這個(gè)插件的問(wèn)題在于,如果是無(wú)效的代碼塊,比如在else代碼塊只做了console.log操作,并不會(huì)檢測(cè)出來(lái)。 另外,較為復(fù)雜的條件判斷盡量拆成單獨(dú)的變量,并分別配上注釋說(shuō)明,這樣可以防止邏輯處理漏。

          2.5 存在無(wú)意義的 catch 代碼塊

          和無(wú)意義的 else 代碼塊一樣,也存在空catch代碼塊、只有console.log的catch代碼塊的情況。

          // bad case
          try {
            doSomething();
          } catch (e) {
          }
          
          // bad case
          try {
            doSomething();
          } catch (e) {
            console.log(e);
          }
          
          // bad case
          somePromise().then(()=> {
            doSomething()
          }).catch(()=> {
          })
          
          somePromise().then(()=> {
            doSomething()
          }).catch((e)=> {
            console.log(e)
          })
          

          為了解決這個(gè)問(wèn)題,醫(yī)典這邊做了一個(gè)eslint插件@tencent/eslint-plugin-medical,能夠檢查try catch里的catch代碼塊、promise 的catch代碼塊,是否為空,是否只有console調(diào)用。cuow當(dāng)然,有些時(shí)候,并不需要對(duì)異常邏輯進(jìn)行額外業(yè)務(wù)邏輯處理,catch里可以加一個(gè)上報(bào)。

          2.6 是否含有安全風(fēng)險(xiǎn)的代碼

          這一步可以在流水線里接入安全風(fēng)險(xiǎn)檢測(cè)插件進(jìn)行處理。以下是醫(yī)典接入后的一個(gè)示例分析


          確實(shí)存在一些誤判,比如會(huì)把mixin關(guān)鍵字當(dāng)做泄露人名來(lái)進(jìn)行告警,開(kāi)發(fā)人員可以對(duì)照分析是否需要處理。

          An

          前端常見(jiàn)的硬編碼場(chǎng)景有:

          • 請(qǐng)求參數(shù)和返回對(duì)象 比如之前就遇到過(guò),開(kāi)發(fā)同學(xué)把mock的請(qǐng)求參數(shù)id,放到了線上的情況。(因?yàn)樵摻涌谑歉鶕?jù)醫(yī)生id,拉取評(píng)論,評(píng)論也是后端灌的假數(shù)據(jù),所以在測(cè)試階段都沒(méi)發(fā)現(xiàn))
          // 請(qǐng)求參數(shù)硬編碼
          getCommentsApi({ doctorId: 1 }).then((res)=> {
            doSomething()
          }).catch(()=> {
            handleError();
          })
          

          也出現(xiàn)過(guò)ABtest接口,開(kāi)發(fā)同學(xué)本地模擬返回對(duì)象,忘記刪除硬編碼的情況

          fetchABTestApi().then((res)=> {
            // res.data
            const obj={
              imgSrc: 'xxx',
              name: 'qinmu'
            }
          })
          

          接口mock的硬編碼,完全可以通過(guò)使用mock平臺(tái)來(lái)解決。推薦使用專(zhuān)業(yè)的接口管理平臺(tái)來(lái)進(jìn)行接口管理、mock等,這里我們使用的是騰訊內(nèi)部接口管理平臺(tái)tolstoy。該產(chǎn)品還未正式開(kāi)源,歡迎提前關(guān)注。

          • 路由參數(shù)
          // bad case 硬編碼1001
          const isActive=this.$route.query.id==='1001'
          
          // good case 寫(xiě)到配置信息中。這樣,id和狀態(tài)的對(duì)應(yīng)關(guān)系一目了然,便于管理和維護(hù)。
          const idConfig={
            1001: STATUS.ACTIVE
          }
          const isActive=idConfig[this.$route.query.id]===STATUS.ACTIVE
          

          2.8 格式校驗(yàn)

          輸入框的校驗(yàn)規(guī)則除了滿足產(chǎn)品需求,比如多少字符以內(nèi)、允許哪些字符,還有一個(gè)點(diǎn):前后端需要校驗(yàn)規(guī)則保持一致。最好用統(tǒng)一的正則表達(dá)式,不然容易造成前端校驗(yàn)通過(guò)、后端校驗(yàn)不通過(guò)的情況。

          上傳文件,前后端需求校驗(yàn)文件格式、文件大小。尤其是后端,需要對(duì) content-type 為 text/html 的加以限制,防止出現(xiàn)安全問(wèn)題。我們已經(jīng)有過(guò)此類(lèi)安全問(wèn)題的工單了。

          3. 代碼習(xí)慣

          3.1 if-else嵌套不能超過(guò)4層

          拒絕面條代碼,減少代碼中各種結(jié)構(gòu)的嵌套,例如 if-else、try-catch、循環(huán)等。盡量控制在三層以內(nèi),增加可讀性、降低圈層復(fù)雜度。 你肯定不愿意維護(hù)這樣辣眼睛的代碼:

          async getConfig(id, type='', isReset=false) {
            try {
              if (liveid) {
                 const res=await someApi(id);
                 if (res && res.info) {
                   const { status }=res.info
                   status===2 && doA({id, type});
                   if (status===1 || status===2 || status===4) {
                     this.setData({
                       info: res.info,
                       status,
                     })
                     if (isReset) {
                       this.setData({
                         current: 0,
                         index: 0
                       })
                       status===2 && doB();
                     }
                     return { code: 0};
                   }
                   return doC();
                 } else if (isReset) {
                   resetSomething();
                 } else if (isReset && type===someType) {
                   handleType();
                 }
                 return wx.showModal({ //... })
              }
            } catch (error) {
              if (error.code===1001) {
                reportA();
              } else {
                reportB();
                doD();
              }
            }
          }
          

          3.2 Don't repeat yourself

          邏輯相同或相似的代碼,應(yīng)封裝為函數(shù)進(jìn)行調(diào)用。

          // bad case 都有展示modal的邏輯,開(kāi)發(fā)同學(xué)直接復(fù)制粘貼
          function handleA(msg) {
            wx.showModal({
              title: '提示',
              content: msg,
              showCancel: false,
              confirmText: '確定',
              confirmColor: '#02BACC',
              success: (res)=> {
                if (res.confirm) {
                  doA();
                 }
               },
            });
          }
          
          function handleB(msg) {
            wx.showModal({
              title: '提示',
              content: msg,
              showCancel: false,
              confirmText: '確定',
              confirmColor: '#02BACC',
              success: (res)=> {
                if (res.confirm) {
                  doB();
                 }
               },
            });
          }
          
          function handleC(msg) {
            wx.showModal({
              title: '提示',
              content: msg,
              showCancel: false,
              confirmText: '確定',
              confirmColor: '#02BACC',
              success: (res)=> {
                if (res.confirm) {
                  doC();
                 }
               },
            });
          }
          

          解決方案,封裝showModal函數(shù)。

          function showModal (msg) {
            return new Promise((resolve, reject)=> {
              wx.showModal({
                title: '提示',
                content: msg,
                showCancel: false,
                confirmText: '確定',
                confirmColor: '#02BACC',
                success: (res)=> {
                  if (res.confirm) resolve()
                },
                fail: (err)=> {
                  reject(err)
                }
              })
            })
          }
          
          funtion handleA(msg) {
            showModal(msg).then(
              doA();
            ).catch(()=> { catchHandler();})
          }
          
          funtion handleB(msg) {
            showModal(msg).then(
              doB();
            ).catch(()=> { catchHandler();})
          }
          
          funtion handleC(msg) {
            showModal(msg).then(
              doC();
            ).catch(()=> { catchHandler();})
          }
          

          3.3 不建議直接修改Object原型(或者Function, Array原型等)

          在Object.prototype上定義方法就相當(dāng)于C++里定義宏, 而且還是 #define private public 這種。 從可靠性來(lái)說(shuō),多人協(xié)作很容易出現(xiàn)沖突。 從兼容性來(lái)說(shuō),你不能保證后續(xù)推出的原生方法實(shí)現(xiàn)和你現(xiàn)有的一致,也不能保證多個(gè)庫(kù)之間對(duì)該方法的實(shí)現(xiàn)一致。比較有名的故事是 prototype庫(kù)的getElementsByClassName。在還沒(méi)有這個(gè)原生方法之前,prototype這個(gè)庫(kù)實(shí)現(xiàn)的是返回Array,并且加了“each”方法:document.getElementsByClassName('myclass').each(doSomething);但原生方法出來(lái)后,返回的是NodeList,并沒(méi)有each方法;所以就悲劇了。 詳細(xì)說(shuō)明可以看:Nicholas C. Zakas 的 Maintainable JavaScript: Don’t modify objects you don’t own

          3.4 回調(diào)嵌套不建議超過(guò)3層回調(diào)嵌套

          減少回調(diào)的嵌套,避免產(chǎn)生callback hell:

          fs.readdir(source, function (err, files) {
            if (err) {
              console.log('Error finding files: ' + err)
            } else {
              files.forEach(function (filename, fileIndex) {
                console.log(filename)
                gm(source + filename).size(function (err, values) {
                  if (err) {
                    console.log('Error identifying file size: ' + err)
                  } else {
                    console.log(filename + ' : ' + values)
                    aspect=(values.width / values.height)
                    widths.forEach(function (width, widthIndex) {
                      height=Math.round(width / aspect)
                      console.log('resizing ' + filename + 'to ' + height + 'x' + height)
                      this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
                        if (err) console.log('Error writing file: ' + err)
                      })
                    }.bind(this))
                  }
                })
              })
            }
          })
          

          建議使用promise、async/await 的方式讓代碼更為清晰可讀;也可以將callback要做的事拆成獨(dú)立的function,并分別對(duì)err進(jìn)行處理。

          3.5 函數(shù)不超過(guò)80行

          函數(shù)盡量精簡(jiǎn)在80行以內(nèi),并且以小function進(jìn)行組織,方便維護(hù)、復(fù)用。

          3.6 缺少注釋及注釋規(guī)范化

          除了知道下面的邏輯是在繪制canvas,其他邏輯你能看懂嗎?

          function doSomething() {
                let count;
                if ((count=width * height / 1000000) > 1) {
                  count=~~(Math.sqrt(count) + 1);
                  const nw=~~(width / count);
                  const nh=~~(height / count);
                  const tCanvas=document.createElement('canvas');
                  const tctx=tCanvas.getContext('2d');
                  tCanvas.width=nw;
                  tCanvas.height=nh;
          
                  for (let i=0; i < count; i++) {
                    for (let j=0; j < count; j++) {
                      tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh);
                      ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);
                    }
                  }
                } else {
                  ctx.drawImage(img, 0, 0, width, height);
                }
          }
          

          常用的注釋分類(lèi)有這些,建議參考 JSDoc:

          1)文件注釋

          2)變量注釋

          3)常量注釋

          4)函數(shù)注釋

          5)枚舉注釋

          6)類(lèi)的注釋

          7)類(lèi)的屬性注釋

          3.7 注釋與實(shí)現(xiàn)功能不符

          這一條在團(tuán)隊(duì)里是出現(xiàn)過(guò)現(xiàn)網(wǎng)bug的。

          故事背景是開(kāi)發(fā)M在重構(gòu)代碼時(shí),設(shè)置底部欄狀態(tài)這一邏輯已經(jīng)封裝出來(lái),所以根據(jù)注釋?zhuān)旅鎺仔写a做的事情也是設(shè)置底部欄狀態(tài),開(kāi)發(fā)M就把這幾行代碼都刪掉了。但是注釋下面的代碼,除了做設(shè)置底部欄狀態(tài)的事情,還有一個(gè)setBanner 函數(shù),是為了設(shè)置banner位的,也被連同刪掉,進(jìn)而導(dǎo)致了bug。

          追溯原因,設(shè)置底部欄狀態(tài)是A同學(xué)做的,設(shè)置 banner 位是B同學(xué)做的,B同學(xué)在沒(méi)有看注釋的情況下,直接把setBanner放在了錯(cuò)誤的位置上。

          function fetchData() {
            // ...
            doManythings();
            
            // 設(shè)置底部欄狀態(tài)
            setBanner();
            fetchStatusApi().then(res=> {
              // ...
            }).catch(()=> {
              // ...
            })
          }
          

          3.8 避免存在大量注釋掉的無(wú)用代碼

          git的版本管理能幫我們回溯之前的代碼。如果項(xiàng)目里存在大量注釋掉的代碼,會(huì)降低可讀性。

          3.9 避免遺留大量多余的console.log調(diào)試日志

          雖然console.log調(diào)試日志在生產(chǎn)環(huán)境構(gòu)建時(shí)不會(huì)輸出,但就本地開(kāi)發(fā)環(huán)境來(lái)說(shuō),代碼里慘雜過(guò)多console.log調(diào)試日志,控制臺(tái)滿屏的調(diào)試日志,對(duì)于每個(gè)接手的開(kāi)發(fā)都是噩夢(mèng)。另外,就像上面說(shuō)的一樣,catch處理或else分支里存在只打console.log而不做任何處理的情況。盡量避免少使用console.log,也可以減少這類(lèi)意外的發(fā)生。

          所以,日常開(kāi)發(fā)調(diào)試建議使用瀏覽器sources tab的斷點(diǎn)調(diào)試;另外,就算要輸出調(diào)試日志,也不止有console.log可以使用,參考這篇文章。你可以使用console.table等來(lái)格式化輸出

          3.10 存在很多eslint-disable注釋

          我能想到的允許 eslint-disable的場(chǎng)景只有一種,那就是解構(gòu)后端返回對(duì)象。后端返回對(duì)象屬性名是下劃線,這個(gè)時(shí)候可能需要 // eslint-disable-next-line camelcase。其他情況我都不建議使用 eslint-disable,尤其是整個(gè)文件全局eslint-disable。

          之前遇到過(guò)某文件全局禁用"no-undef"規(guī)則,結(jié)果代碼里使用了未定義的變量,導(dǎo)致現(xiàn)網(wǎng)bug。如果你有全局定義的變量,建議寫(xiě)在eslintrc.js的globals字段里。當(dāng)然,就正如上文代碼錯(cuò)誤-內(nèi)存泄露提到的一樣,非必要情況,不建議使用全局變量。

          3.11 沒(méi)有使用空行對(duì)代碼分組

          為了增強(qiáng)可讀性,建議使用空行對(duì)代碼分組。

          3.12 命名規(guī)范

          常見(jiàn)的不規(guī)范命名有這些,會(huì)讓之后維護(hù)的同學(xué)很懵逼:

          • 單詞拼寫(xiě)錯(cuò)誤,比如submitForm,寫(xiě)成submitFrom。
          • 中英文混用。比如gotoZaihai。你能知道這是什么意思嗎?其實(shí)是跳到災(zāi)害專(zhuān)區(qū)活動(dòng)頁(yè)。goToDisasterZone是不是要好一點(diǎn),同學(xué)?
          • 以1-9、a-z命名 在項(xiàng)目里我曾經(jīng)見(jiàn)過(guò)不知道怎么命名,就type1、type2、type3直接上了,也不寫(xiě)注釋。非常讓人抓狂。
          • 混用命名格式 就評(píng)論列表,代碼里有comments、commentList、也有commentData、commentsData。???能規(guī)范統(tǒng)一一下嗎。
          • 單復(fù)數(shù)不分 明明是一個(gè)列表數(shù)據(jù),非要用單數(shù)表示,比如 disease。建議區(qū)分下單復(fù)數(shù),如果是數(shù)組就用List來(lái)表示。
          • 動(dòng)詞、名詞、形容詞不分 比如,一個(gè)函數(shù)名,命名為名詞“doctor”;而一個(gè)Vue computed屬性,又命名為getUserInfo;表示關(guān)閉狀態(tài),命名為“close”;真是讓人非常頭疼。
          // bad case 1
          function doctor () {}
           
          // bad case 2
          computed: {
            getUserInfo() {}   
          }
          
          // bad case 3
          close=false; 
          

          同學(xué),就不能好好寫(xiě)代碼嗎?

          // good case 1
          function getDoctorInfo() {}
          
          // good case 2
          computed: {
            getUserInfo() {}   
          }
          
          // good case 3
          closed=false
          

          3.13 過(guò)多的非業(yè)務(wù)邏輯相關(guān)代碼(如超過(guò)10行的上報(bào), 參雜在業(yè)務(wù)邏輯里)

          如果在業(yè)務(wù)邏輯里摻雜太多的上報(bào),后續(xù)理解業(yè)務(wù)邏輯時(shí)需要看上報(bào)邏輯,查上報(bào)邏輯的時(shí)候也需要理解大量的業(yè)務(wù)代碼。 點(diǎn)擊埋點(diǎn)和曝光埋點(diǎn)都可以以屬性的形式掛在元素上,通過(guò)冒泡,統(tǒng)一進(jìn)行處理。

          <button
          	data-exposurename="test-exposure"
          	:data-exposureval="{event:'bottom.btn'} | jsonStringify"
            data-eventname="button.click"
            :data-eventval="{id: buttonId} | jsonStringify"
          />
          

          如果你上報(bào)的參數(shù)需要根據(jù)不同渠道來(lái)配置,建議封裝出來(lái),不要和業(yè)務(wù)邏輯耦合了。

          3.14 沒(méi)有README文檔、或者README太簡(jiǎn)單、太作用有限

          除了項(xiàng)目的READMD,每個(gè)模塊都應(yīng)該有各自的README,說(shuō)明這個(gè)模塊的功能點(diǎn)、技術(shù)實(shí)現(xiàn)方案等。看個(gè)人習(xí)慣,你也可以寫(xiě)在iwiki里,在README放一個(gè)iwiki的鏈接。

          3.15 盡量使用export 而 不是 export default來(lái)導(dǎo)出

          export default 有兩個(gè)問(wèn)題: 1)不利于tree shaking 2)如果使用了一個(gè)導(dǎo)出對(duì)象上不存在的屬性,要運(yùn)行時(shí)才能發(fā)現(xiàn)。

          4.代碼優(yōu)化【持續(xù)更新中】

          4.1 避免大量直接操作dom節(jié)點(diǎn)

          直接操作DOM的性能損耗至少有兩個(gè)地方:進(jìn)行DOM操作的時(shí)候上下文切換 + DOM操作引起的頁(yè)面重繪

          4.2 避免使用delete

          delete 操作符并不會(huì)釋放內(nèi)存,而且會(huì)使得附加到對(duì)象上的hidden class失效,讓對(duì)象變成slow object。 (hidden class是V8為了優(yōu)化屬性訪問(wèn)時(shí)間而創(chuàng)建的隱藏類(lèi)) 來(lái)看一下執(zhí)行速度對(duì)比:undefined > delete > omit

          4.3 是否引用了不必要的npm包

          比如做一個(gè)簡(jiǎn)單圖表的需求,不選輕量的庫(kù),非要整一個(gè)echarts;或者實(shí)現(xiàn)一個(gè)簡(jiǎn)單的代碼編輯器,monaco-editor有min版本不使用,非要引用一整個(gè)monaco-editor。還有,lodash沒(méi)法做tree-shaking,要么引用一個(gè)具體的子包lodash.get,要么引用lodash-es,非要引用一整個(gè)lodash。

          4.4 盡量使用CDN地址的圖片

          如果代碼里引用的是本地圖片,構(gòu)建打包會(huì)有耗時(shí)。可以在引用之前就把圖片傳到cdn上,代碼里直接使用cdn地址。

          以上就是CR的細(xì)則了。

          手都寫(xiě)麻了。當(dāng)然,肯定還有很多遺漏的點(diǎn),歡迎補(bǔ)充。

          信圍觀的讀者不是初來(lái)乍到的小白,在這里不多贅述亞馬遜review的歷史變遷以及重要性。一段時(shí)間以來(lái)我們集中處理amazon review問(wèn)題,時(shí)至今日有了亞馬遜測(cè)評(píng)系統(tǒng)(以下簡(jiǎn)稱(chēng)系統(tǒng))也有了一些明確思路。一路走來(lái),也參加了市面上大大小小的review課程,但這些review攻略偏灰色,不成體系。今天的終極攻略希望能從亞馬遜review的整體布局思路和具體方法上給予讀者一定的啟發(fā)和幫助。通過(guò)本篇文章,你將獲得:

          1.亞馬遜review維護(hù)全局框架

          2.多渠道多策略建立亞馬遜測(cè)評(píng)體系

          3.不同補(bǔ)評(píng)(測(cè)評(píng))策略時(shí)效性,安全性,可持續(xù)性以及成本對(duì)比分析

          4.真人測(cè)評(píng)與刷單上評(píng)的識(shí)別與開(kāi)發(fā)

          5.新品LISTING安全快速補(bǔ)評(píng)方法

          6.如何通過(guò)自動(dòng)化補(bǔ)評(píng)規(guī)則提高評(píng)價(jià)維護(hù)效率

          溫馨提示:

          為了避諱一些敏感字眼,賓果博客內(nèi)定義所有人為干預(yù)的上評(píng)行為均稱(chēng)為補(bǔ)評(píng),所有人為干預(yù)的出單行為均稱(chēng)為補(bǔ)單

          影響亞馬遜關(guān)鍵詞排名因素千千萬(wàn),相關(guān)性、轉(zhuǎn)化率與用戶反饋(review)至關(guān)重要。在review方面(本文不講轉(zhuǎn)化率):新品,我們希望短時(shí)間內(nèi)有足夠高質(zhì)量和足夠數(shù)量的review上線,既是為了在新品扶持期內(nèi)加快新品推廣進(jìn)展,也是為了規(guī)避差評(píng)風(fēng)險(xiǎn)。老品,我們希望零差評(píng)的同時(shí)每個(gè)月都有成比例的好評(píng)上線。滿懷期待,但有時(shí)卻力不從心,把以下四項(xiàng)策略堅(jiān)持執(zhí)行到位即可解決亞馬遜review中的90%的問(wèn)題:

          1.亞馬遜review差評(píng)預(yù)防

          在產(chǎn)品Listing的評(píng)分里,1個(gè)差評(píng)可以抹掉5個(gè)好評(píng),換句話說(shuō)5個(gè)好評(píng)只可以抹掉1個(gè)差評(píng)。對(duì)很多從事亞馬遜運(yùn)營(yíng)的賣(mài)家來(lái)說(shuō),差評(píng)本身不易移除,這將會(huì)對(duì)抵抗力不強(qiáng)的LISTING銷(xiāo)量帶來(lái)毀滅性打擊。亞馬遜review差評(píng)的危害巨大,一定是以預(yù)防為主。

          2.亞馬遜review差評(píng)移除

          兵來(lái)將擋,水來(lái)土掩。差評(píng)來(lái)了也莫怕,據(jù)相關(guān)經(jīng)驗(yàn),亞馬遜review差評(píng)有30%-50%移除的概率,當(dāng)然有很多深圳大賣(mài)能做到50%或更高。

          3.亞馬遜測(cè)評(píng)(快速補(bǔ)評(píng))

          今天的一個(gè)重頭戲,相信也是各位讀者最想了解的一部分。本文將從時(shí)效性.安全性.可持續(xù)性以及成本四個(gè)維度展開(kāi)不同測(cè)評(píng)渠道的講解。前期建議以服務(wù)商的真人測(cè)評(píng)放單為主,同時(shí)快速建立起自己的測(cè)評(píng)體系。等體系建立后,用自己的方法更安全。

          4.自動(dòng)化補(bǔ)評(píng)規(guī)則

          我們需要更高的測(cè)評(píng)效率,不僅僅是打通測(cè)評(píng)渠道更要建立自動(dòng)化的測(cè)評(píng)管理。在不人為干預(yù)的情況下,評(píng)價(jià)維護(hù)負(fù)責(zé)人即使不懂亞馬遜運(yùn)營(yíng)也明白什么時(shí)間該對(duì)什么產(chǎn)品補(bǔ)評(píng)了,哪些產(chǎn)品需要優(yōu)先處理等等。這對(duì)多賬戶多Listing操作的賣(mài)家有很大幫助。

          接下來(lái)從策略到方法,從方法到執(zhí)行,一步步分解亞馬遜review維護(hù)。

          亞馬遜review差評(píng)預(yù)防攻略

          1.采購(gòu)端

          第一,明確質(zhì)檢方向讓懂產(chǎn)品的人做質(zhì)檢工作。特別注意的一點(diǎn)是應(yīng)考慮產(chǎn)品在亞馬遜上經(jīng)常遇到的差評(píng)內(nèi)容,讓懂產(chǎn)品的人做有針對(duì)性的質(zhì)檢工作。第二,100%質(zhì)檢。按照亞馬遜0.5%-1%的留評(píng)率計(jì)算,如果100件商品內(nèi)有1件的瑕疵品,意味著所有的自然留評(píng)全是差評(píng),夠恐怖吧。但傳統(tǒng)大貿(mào)環(huán)境下,工廠都是習(xí)慣進(jìn)行抽檢工作,很難保證0.5%內(nèi)的瑕疵率。所以當(dāng)從事亞馬遜B2C電商與工廠打交道時(shí),務(wù)必確認(rèn)100%的質(zhì)檢率。哪怕每件多付1元的質(zhì)檢費(fèi)用,也要保證不出現(xiàn)因?yàn)樯唐焚|(zhì)量瑕疵帶來(lái)的差評(píng)。

          案例:2018年4月上架了一批魚(yú)竿產(chǎn)品,通過(guò)推廣陸陸續(xù)續(xù)有了穩(wěn)定的訂單。時(shí)間進(jìn)入5月,接連出現(xiàn)差評(píng)和退貨,處理差評(píng)和上評(píng)的速度跟不上差評(píng)的速度(那時(shí)也沒(méi)有一套完整評(píng)價(jià)維護(hù)體系),結(jié)果可想而知。后來(lái)找到原因:本批次魚(yú)竿采用了分體輪座的技術(shù),好處是讓魚(yú)竿更輕但是因?yàn)檩喿煮w很容易導(dǎo)致漁輪和輪座卡不緊。魚(yú)竿體積比較大,沒(méi)經(jīng)過(guò)自己的倉(cāng)庫(kù)直接運(yùn)輸?shù)礁劭诔鲐洠己鲆暳速|(zhì)檢。

          2.銷(xiāo)售端

          文案嚴(yán)謹(jǐn),說(shuō)明注意事項(xiàng)。文案描述不要夸大產(chǎn)品,避免因與用戶期望值不符帶來(lái)的差評(píng)。同時(shí)更要描述清楚產(chǎn)品的適用范圍、適用人群,注意事項(xiàng),避免誤解誤用帶來(lái)的差評(píng)。

          案例:一段時(shí)間發(fā)現(xiàn)有些客戶反映某些魚(yú)竿的輪座和他們的漁輪不適配。后來(lái)發(fā)現(xiàn):原來(lái)是文案和圖片描述說(shuō)本產(chǎn)品適用于多種漁輪,一是給用戶的錯(cuò)覺(jué)是適用于所有漁輪,至少適用于他手中的漁輪。二是,既然提出魚(yú)竿漁輪適配情況卻未給出嚴(yán)謹(jǐn)?shù)谋磉_(dá)。所以當(dāng)用戶用不上自己的漁輪時(shí),心情很不爽。

          3.客服端

          如果前面1&2沒(méi)有做到位,還有差評(píng)預(yù)防的補(bǔ)救措施:在用戶很不爽的時(shí)候第一時(shí)間能找到最簡(jiǎn)單快捷的發(fā)泄渠道。而作者認(rèn)為感謝卡,產(chǎn)品以及包裝上的聯(lián)系方式最為方便客戶聯(lián)系到你,這樣用戶就會(huì)聯(lián)系你發(fā)泄不滿代替登錄后臺(tái)留差評(píng)。用了這個(gè)方法后,在ins或者facebook上陸陸續(xù)續(xù)接到了客戶的一些不滿反饋,極大降低了留差評(píng)的可能性,不僅如此通過(guò)提供解決方案還得到了用戶的認(rèn)可,愿意留好評(píng)!

          總結(jié):能把差評(píng)堵在萌芽中,省心省錢(qián)!差評(píng)預(yù)防中,細(xì)節(jié)即大事!

          亞馬遜review差評(píng)移除攻略

          在review差評(píng)移除中可以很好的用“快,準(zhǔn),狠”三個(gè)字形容:出現(xiàn)差評(píng)反應(yīng)要快,移除方法切入點(diǎn)要準(zhǔn),雙管齊下力道要狠。那么如何做到快速反應(yīng),切入要害,雙管齊下呢,我們首先看一下差評(píng)移除的幾個(gè)重要方法:服務(wù)商移除,溝通移除,亞馬遜移除。

          1.服務(wù)商移除

          服務(wù)商移除差評(píng)作者很少用,一是因?yàn)闇贤ㄒ瞥蛠嗰R遜移除的效果還可以,二是因?yàn)橘M(fèi)用高,三是因?yàn)楦鱾€(gè)服務(wù)商移除差評(píng)的方法層出不窮自己沒(méi)法控制過(guò)程風(fēng)險(xiǎn)比較高。之所以在這里提出,是給到大家一個(gè)應(yīng)急的方法:既然出來(lái)做差評(píng)服務(wù),我想在時(shí)效上和成功率上應(yīng)該都不錯(cuò)。當(dāng)差評(píng)嚴(yán)重影響自己的時(shí)候可以考慮使用。

          2.溝通移除 (此方法本身不難,難點(diǎn)在時(shí)間節(jié)點(diǎn)控制和郵件內(nèi)容)

          溝通移除是指獲取用戶真實(shí)郵箱后,通過(guò)幫助解決問(wèn)題或者給予一定補(bǔ)償?shù)玫接脩粽徑夂驼J(rèn)可,繼而要求刪掉/修改差評(píng)的過(guò)程。

          @節(jié)點(diǎn)1.記錄所留差評(píng),記錄時(shí)間。力保第一時(shí)間發(fā)現(xiàn)差評(píng),快速獲取真實(shí)郵箱。

          @節(jié)點(diǎn)2.記錄真實(shí)郵箱,記錄獲取的時(shí)間。市面上有很多獲取真實(shí)郵箱的途徑,15-25元不等。2個(gè)工作日內(nèi)獲取郵箱,不要拖太久。

          @節(jié)點(diǎn)3.發(fā)送郵件聯(lián)系,記錄發(fā)送時(shí)間。獲取郵箱后,按照制定好的標(biāo)準(zhǔn)郵件內(nèi)容發(fā)送。

          @節(jié)點(diǎn)4.獲得客戶反饋,記錄反饋時(shí)間 。到此步,收到反饋進(jìn)入下一步。經(jīng)常收不到反饋需要考慮重新編輯郵件內(nèi)容,偶爾收不到反饋考慮用戶可能沒(méi)有看到郵件,在跟一封“Friendly reminder”

          @節(jié)點(diǎn)5.根據(jù)郵件要求,給予問(wèn)題解決或給予補(bǔ)償操作。

          @節(jié)點(diǎn)6.按用戶要求完成后,用戶自己知道要?jiǎng)h除評(píng)價(jià)。

          除時(shí)間節(jié)點(diǎn)跟蹤好外,此方法最有技術(shù)含量的是節(jié)點(diǎn)3的郵件內(nèi)容。做好郵件內(nèi)容的要點(diǎn),一是郵件主旨內(nèi)容(直奔主題就好):愿意為review做出補(bǔ)償。這一點(diǎn)非常重要。只要用戶回復(fù),意味著用戶默許了你的建議,只要做了補(bǔ)償,用戶就得處理差評(píng)。二是補(bǔ)償建議:必須有方案,給到用戶A與B的選擇,要知道用戶是沒(méi)時(shí)間給你瞎掰的,除非你的產(chǎn)品貨值很高。三是郵件Title:能不能打開(kāi)你的郵件,就看你的TITLE用不用心了。通過(guò)以上幾點(diǎn)反復(fù)斟酌自己的郵件內(nèi)容,一定會(huì)事半功倍。

          3.亞馬遜移除(此方法難點(diǎn)在找準(zhǔn)切入點(diǎn))

          亞馬遜有review留評(píng)的明確條文,凡是不符合亞馬遜規(guī)則的評(píng)價(jià)都將予以刪除,并不允許在此LISTING再次留評(píng)。我們要做的是合理利用亞馬遜規(guī)則,向亞馬遜客服提出所處理差評(píng)的不合理性。鏈接www.amazon*com/gp/help/customer/display.html?nodeId=201929730是亞馬遜review的一些規(guī)則,空了可以細(xì)細(xì)品讀。根據(jù)以上規(guī)則和實(shí)戰(zhàn)經(jīng)驗(yàn)總結(jié)如下:

          @規(guī)則1.review與feedback混淆。review僅是涉及物流客服包裝等服務(wù)方面的內(nèi)容。

          @規(guī)則2.含誹謗,騷擾,威脅,煽動(dòng)性,淫穢,色情或猥褻內(nèi)容

          @規(guī)則3.含個(gè)人隱私內(nèi)容

          @規(guī)則4:含促銷(xiāo)內(nèi)容

          @規(guī)則5:差評(píng)專(zhuān)業(yè)戶留評(píng)

          @規(guī)則6:內(nèi)容積極但星級(jí)是差評(píng)

          …………..

          找準(zhǔn)切入點(diǎn)后有3處提交入口;1是Report Abuse , 2是后臺(tái)幫助中的amazon review板塊 ,3是community-help*amazon.com.為了達(dá)到更好的效果,溝通移除與亞馬遜移除同步進(jìn)行,雙管齊下,收效更好!

          本章亞馬遜review維護(hù)攻略梳理到這里,下個(gè)章節(jié)將詳述市面上主流的亞馬遜測(cè)評(píng)渠道補(bǔ)評(píng)方法并從時(shí)效性、安全性、可持續(xù)性和費(fèi)用四個(gè)維度進(jìn)行分析,最后帶給大家如何建立快速補(bǔ)評(píng)自動(dòng)化規(guī)則。


          主站蜘蛛池模板: 国产不卡视频一区二区三区| 久久亚洲中文字幕精品一区四 | 好爽毛片一区二区三区四| 国产成人无码AV一区二区在线观看| 一区二区中文字幕在线观看| 亚洲乱码一区二区三区在线观看| 香蕉久久一区二区不卡无毒影院| 91久久精品国产免费一区| 国产亚洲一区二区三区在线观看| 国产一区二区三区夜色| 精品成人乱色一区二区| 日本精品高清一区二区2021| 日本免费一区二区久久人人澡| 亚洲成av人片一区二区三区| 中文字幕一区视频| 成人无码AV一区二区| 无码精品人妻一区| 精品无人区一区二区三区| 精品亚洲一区二区三区在线播放| 国产成人精品久久一区二区三区| 午夜影视日本亚洲欧洲精品一区 | 亚洲色偷偷偷网站色偷一区| 在线观看国产区亚洲一区成人| 亚洲熟女乱综合一区二区| 一区二区三区在线观看视频| 日韩精品一区二区三区毛片| 无码夜色一区二区三区| 精品无码一区二区三区亚洲桃色| 精品无码成人片一区二区98| 后入内射国产一区二区| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 视频一区视频二区制服丝袜| 91精品一区二区三区久久久久| 国产在线精品一区二区中文| 无码人妻AⅤ一区二区三区| 丰满人妻一区二区三区视频| 久久久不卡国产精品一区二区| 激情综合一区二区三区| 一区二区三区精品视频| 久久人妻无码一区二区| 无码欧精品亚洲日韩一区夜夜嗨|