uni-app小程式(快手)日誌列印坑位記錄

!win !發表於2024-08-27

前情

uni-app是我比較喜歡的跨平臺框架,它能開發小程式/H5/APP(安卓/iOS),重要的是對前端開發友好,自帶的IDE讓開發體驗也挺棒的,公司專案就是主推uni-app。

坑位

最近在開發一需求,頁面上的內容需要根據當前主查詢介面返回的某一個欄位A是否為null來做介面輪詢,直到它獲取到非null的真正內容,在開發者工具一切都正常,但在真機快手小程式上測試時並沒有觸發頁面介面輪詢,導致頁面資料顯示異常。

於是我透過小程式控制臺檢視,發現確實欄位A是非null值,但又不是介面文擋上註明的值,我開始懷疑是服務端資料返回問題,把截圖甩給服務端說資料返回不太對,服務端向我要了請求引數後,他透過postman模擬請求,說資料是對的,我在小程式開發者工具控制檯上看了介面資料確實也是對的,重新測了真機確實是不行的,因為專案我是中間接手的,我懷疑是不是程式碼請求的封裝方法中有什麼騷操作,於是仔細review了一遍通用請求封裝的方法,除了找到一個可以最佳化的點外,並沒有發現有什麼不妥當的地方。

Why?

我猜應該是快手小程式的vConsole在日誌列印不知道做了什麼操作修改了物件中欄位為null的資料,目前發現的是null會被替換為當前傳入的整個物件,無限迴圈下去,導致頁面獲取不到介面返回的原始資料,導致功能異常。於是我在快手小程式論壇提了貼子,反映了目前遇到的問題,連結:開發小程式日誌輸出異常 (kuaishou.com)

幾小時後官方就給了我回復說,沒有重現出來,我於是新建一個最小專案,重現了下問題,最小示例專案很簡單就是一個頁面,純列印我專案中介面返回的測試資料日誌:

<template>
	<view class="content">
		<view class="text-area">
			首頁
		</view>
		<button @click="log">輸出日誌</button>
	</view>
</template>

<script setup>
let logObj = {
    "status": "success",
    "code": 200,
    "message": "操作成功",
    "data": {
        "order": {
            "id": 21184,
            "platform": 9,
            "order_no": "662955300914989888",
            "order_mode": 1,
            "state": 11,
            "cancel_status": 441,
            "address_id": 685,
            "shop_id": 0,
            "user_id": 464,
            "payment_funder_mark": "YUE_RONG_ZHONG_KE",
            "source_platform": 2,
            "source_order_no": "",
            "capital_order_id": "3252408100001353",
            "product_id": 11211,
            "sku_id": 28081,
            "id_card_name": "澤城",
            "id_phone": "16249235181",
            "id_card_number": "451581199711097777",
            "security_id": 0,
            "exception_type": 0,
            "risk_decision": 0,
            "total_price": "30.00",
            "first_actual_payment_amount": "1.25",
            "first_payment_rent_payable": "1.25",
            "deposit_total_amount": "10.00",
            "deposit_discount_type": 0,
            "deposit_free_amount": "0.00",
            "deposit_recovery_deduction_amount": "0.00",
            "deposit_actual_amount": "0.00",
            "total_rent": "30.00",
            "buy_out_price": "1.00",
            "buy_out": 0,
            "repaid_amount": "10.00",
            "schemes": 3,
            "lease_days": 720,
            "repayment_periods": 24,
            "courier_number": "",
            "esign_sign_flow_id": "",
            "esign_state": 2,
            "esign_face_flow_id": "",
            "esign_face_state": 0,
            "age": 26,
            "state_exception_note": "",
            "note": "",
            "creator": "",
            "created_at": "2024-08-10 17:55:48",
            "updated_at": "2024-08-10 18:14:15",
            "lease_start_time": "2024-08-14 00:00:00",
            "lease_end_time": "2026-08-04 00:00:00",
            "user_bound_at": null,
            "first_shared_at": null,
            "esign_finish_at": null,
            "task_order_at": "2024-08-10 17:55:48",
            "deleted_at": null,
            "serial_number": "",
            "cancellation_reason": null,
            "sn": "202408108001",
            "contract_file": "/contact/12/18/e38154fbb9ac9308b66e336a01e69a23.pdf",
            "overdue_state": 0,
            "order_process": 1,
            "rent_price_model": 2,
            "payment_mode": 4,
            "conversion_method": 1,
            "deposit_switch": 2,
            "deposit_payment_process": 0,
            "risk_result": 0,
            "sync_supply_chain_time": "2024-08-10 17:58:56",
            "complete_sub_status": 0,
            "verify_delivery_address": 0,
            "cancel_express_status": 2,
            "shipping_phone": "13249235081",
            "source_platform_text": "快手",
            "state_text": "已關閉"
        },
        "order_apply_refund_amount": "0.00",
        "order_refund_examine": {
            "id": 2962,
            "order_no": "662955300914989888",
            "order_state": 4,
            "state": 2,
            "refund_type": 2,
            "refund_reason": 0,
            "audit_time": "2024-08-10 18:14:12",
            "user_id": 25,
            "remark": "訂單退貨退款",
            "reason": "首付太高",
            "deduction_amount": "0.00",
            "deduction_reason": 0,
            "created_at": "2024-08-10 18:11:27",
            "updated_at": "2024-08-10 18:14:16",
            "refund_receive_state": 2,
            "refunded_at": "2024-08-10 18:14:16",
            "examine_no": "SHTH2024081062424559",
            "process": "PASSED",
            "category": 1,
            "mode": 2,
            "force_source_platform": 0,
            "force_out_order_no": "",
            "refund_process": "DEFAULT",
            "refund_return_process": "ALREADY_IN_STOCK",
            "refund_return_courier_number": "SF100862",
            "refund_return_consignee_phone": "13249235081",
            "refund_return_device_expired_time": "2024-08-16 18:12:10",
            "refund_return_device_expired_expend_times": 0,
            "refund_return_express_records": null,
            "refund_return_audit_state": 1,
            "refund_return_audit_time": "2024-08-10 18:12:10",
            "refund_return_reship_consignee_name": "",
            "refund_return_reship_consignee_phone": "",
            "refund_return_reship_consignee_address": "",
            "refund_return_reship_courier_number": "",
            "refund_return_reship_express_records": null,
            "user_remark": "",
            "refund_return_tips": {
                "return_express_tip_info": "請選用順豐快遞(貨到付款)",
                "return_address_tip_info": "18098965084 深圳市福田區世界中心2樓201"
            }
        },
        "is_order_refunded": 1,
        "is_order_allow_apply_refund": 0
    },
    "error": {}
};
const log = () => {
	console.log('---- log ----:', logObj.data.order_refund_examine.refund_return_express_records, logObj);
}
</script>

<style>

</style

解決方案

  1. 註釋掉日誌輸出程式碼(最直接)
  2. 列印日誌的時候列印到特定你想知道的key,或者你想知道的KEY的父級物件,測試中發現層級在一二級不會有問題
  3. 列印前透過JSON.stringify轉化為字串輸出(物件較大的時候很難找到想要看到的key的值)
  4. 深複製後再輸出,雖然列印的日誌是錯的,但是不會影響原始值,至少頁面上拿到的是正確的值,在專案主入口main.js中增加如下程式碼重寫console.log方法是可行的,同時還幫處理了生產環境讓所有log方法失效
const log = console.log;

/**
 * @description 深度克隆
 * @param {object} obj 需要深度克隆的物件
 * @param cache 快取
 * @returns {*} 克隆後的物件或者原值(不是物件)
 */
function deepClone(obj, cache = new WeakMap()) {
	if (obj === null || typeof obj !== 'object') return obj;
	if (cache.has(obj)) return cache.get(obj);
	let clone;
	if (obj instanceof Date) {
		clone = new Date(obj.getTime());
	} else if (obj instanceof RegExp) {
		clone = new RegExp(obj);
	} else if (obj instanceof Map) {
		clone = new Map(Array.from(obj, ([key, value]) => [key, deepClone(value, cache)]));
	} else if (obj instanceof Set) {
		clone = new Set(Array.from(obj, value => deepClone(value, cache)));
	} else if (Array.isArray(obj)) {
		clone = obj.map(value => deepClone(value, cache));
	} else if (Object.prototype.toString.call(obj) === '[object Object]') {
		clone = Object.create(Object.getPrototypeOf(obj));
		cache.set(obj, clone);
		for (const [key, value] of Object.entries(obj)) {
			clone[key] = deepClone(value, cache);
		}
	} else {
		clone = Object.assign({}, obj);
	}
	cache.set(obj, clone);
	return clone;
}

// 重寫日誌輸入方法
console.log = (...params) => {
	if (process.env.NODE_ENV  === "development") {
		const paramsTemp = params.map((item) => {
			return deepClone(item);
		})
		log(...paramsTemp);
	}
}
  1. 和服務端溝通,對於值為null的返回為空字串或者undefined等(不推薦,成本大)

推薦前三種方式,對現有專案沒有任何侵入,方式4也是可以的,這種問題是平臺級的特有BUG,BUG已提給平臺,靜待平臺儘早修復吧。

思考

小程式開發是依賴第三方小程式平臺的,對於一些難定位的問題,自己折騰找不到原因後,可以最佳化論壇搜一搜,如果沒有那就提一個貼子,一般幾天內會有回覆,最好是能做一個最小復現的demo,以便於官方定位問題,做最小demo的時候也許自己也能發現解決或繞過問題的方法,在開發的時候可以依賴開發者工具完成需求,但遇到開發者工具和小程式上表現不一致的時候應該以真機為準,因為你最後專案是跑在真機上的。當然也希望各小程式平臺積極最佳化,給廣大小程式開發者更好的開發體驗。

相關文章