私は過去数日間この質問をオンラインで調査してきましたが、答えは常に「いいえ」であり、ユーザーが留まったか離れたかを確実に判断することはできません (ユーザーが離れた場合にアプリが動作しなくなるという事実を除いて) )。私は「いいえ」という答えが嫌いです。次のユーティリティを思いつきました。
var OnBeforeUnload = (function(){
    var
    FDUM = new Function,
    AFFIRM = function(){ return true; };
    var _reg = function(msg,opts){
        opts = opts || {};
        var
            pid = null,
            pre = typeof opts.prefire == 'function' ? opts.prefire : FDUM,
            callback = typeof opts.callback == 'function' ? opts.callback : FDUM,
            condition = typeof opts.condition == 'function' ? opts.condition : AFFIRM;
        window.onbeforeunload = function(){
            return condition() ? (pre(),setTimeout(function(){ pid = setTimeout(callback,20); },1),msg) : void 0; 
        }
        window.onunload = function(){ clearTimeout(pid); };
    }
    var _unreg = function(){ window.onbeforeunload = null;  }
    return {
        register : _reg,
        unregister : _unreg
    };
})();
したがって、次のような呼び出し
OnBeforeUnload.register('Hello!',{ 
    condition:function_that_returns_true_to_fire_event_false_to_ignore,
    prefire:function_to_call_on_page_exit_attempt, 
    callback:function_to_call_if_user_stays
});
condition がハンドラ内で呼び出され、アクティブ化する必要があるかどうかが確認されます。その場合、ポップアップがユーザーに表示される前に prefire が実行され (ビデオを一時停止したい場合があります)、ユーザーが留まっている場合にのみコールバックが発生します。
私のロジックは、イベント ハンドラーの本体で setTimeout を開始することでした。setTimeout は、ユーザーがいずれかのボタンを押すまで実行されません。彼らがした後、それはすぐに発砲します。この場合の setTimeout はコールバックを呼び出しませんが、20 ミリ秒の遅延でコールバックの別のタイムアウトを実行するプロキシ関数です。ユーザーがページに留まると、コールバックが実行されます。そうでない場合は、コールバックを呼び出すタイムアウトをクリアする別のハンドラが onunload にアタッチされ、コールバックが呼び出されないようにします。私は Firefox、IE、および Chrome でのみ確認する機会がありましたが、これまでのところ 3 つすべてで問題なく動作しています。
これが、この質問に普遍的に与えられた特許「いいえ」に私が不満を抱いていたのと同じくらい人々を助けることを願っています. このコードは完璧ではないかもしれませんが、正しい方向に進んでいると思います。