_pmMarkHandled.mjs

//noop, 無作用之拒絕處理
let noop = () => {}

//PM_THEN, 載入時之內建then(其後Promise.prototype.then被改寫亦不呼叫使用端程式)
const PM_THEN = Promise.prototype.then

//IS_PROMISE, util.types.isPromise(Node 20.16、22.3起經process.getBuiltinModule取得; 以內部槽位判定, 含跨realm, 對Proxy為false且不觸發陷阱); 取不到(瀏覽器、Node<20.16)為null
//只作預檢以省去非Promise之物件於then之品牌檢查所建之例外(成本約數微秒); 取不到時全由then之品牌檢查判定, 結果相同
const IS_PROMISE = (() => {
    try {
        let p = globalThis.process
        let gb = p !== null && typeof p === 'object' ? p.getBuiltinModule : undefined
        if (typeof gb !== 'function') {
            return null
        }
        let u = gb.call(p, 'util')
        let f = u !== null && typeof u === 'object' && u.types !== null && typeof u.types === 'object' ? u.types.isPromise : null
        return typeof f === 'function' ? f : null
    }
    catch (err) {
        return null
    }
})()


/**
 * 對原生Promise預先掛上無作用之拒絕處理,使其標記為已處理,內部共用不對外
 *
 * 用於接收先行產生之Promise陣列而依序或限量取用者(pmSeries、pmMap未給fun時):排在後面之Promise先reject時,若尚未被取用即成為未處理之rejection(Node預設即結束行程),預先標記後其結果仍由原流程取用
 *
 * 以品牌判定原生Promise:直接以載入時之Promise.prototype.then執行(call),非原生Promise者於then之品牌檢查(內部槽位)即拋TypeError而忽略,不讀其任何屬性、不觸發Proxy之陷阱、不呼叫一般thenable之then;
 * 故跨realm(vm新context、iframe)之原生Promise、原型為null或原型被改之原生Promise與子類別之實例皆標記;不經instanceof(其不認跨realm者與原型為null者,且對Proxy會觸發getPrototypeOf陷阱)
 *
 * 原始值直接略過;util.types.isPromise可用時先以之預檢(非Promise者不進then,免建例外之成本),結果與只用then之品牌檢查相同
 *
 * then取得衍生Promise之建構子(species)時會讀原生Promise之constructor與其Symbol.species,子類別或被改寫者其建構子或getter為使用端程式(同instanceof時之既有行為);任何拋錯皆忽略
 *
 * @param {*} v 輸入任意值
 */
function pmMarkHandled(v) {
    if (v === null || (typeof v !== 'object' && typeof v !== 'function')) {
        return
    }
    try {
        if (IS_PROMISE !== null && !IS_PROMISE(v)) {
            return
        }
        PM_THEN.call(v, undefined, noop)
    }
    catch (err) {}
}


export default pmMarkHandled