如何 运行 在 JavaScript 中一个接一个地执行函数?

How to run one function right after another in JavaScript?

我正在 Paypal 上自动执行一项任务,该任务涉及连续单击页面上的几个按钮。

基本上,我需要单击一个单选按钮,然后单击“下一步”按钮以前进到下一页。但是除非先单击单选按钮,否则我无法前进到下一页。

我目前在计时器上有第二个功能,但是有没有办法在第一个功能完成并按下第一个单选按钮后启动第二个功能?

这是我的代码:

// ==UserScript==
// @name     PayPal Transfer Radio
// @include  https://www.paypal.com/myaccount/money/balances/withdraw/balance/*
// @require  http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
// @grant    GM_addStyle
// ==/UserScript==
    
$(function(){
  $('[id="BA-SMSNY4E48EHGC__ACH__STANDARD_FUNDSRadioBtn"]').click()
});

setTimeout(function(){
    $('[name="selectFiNext|standard"]').click();
}, 2000);

setTimeout 方法按原样工作,但不是最佳方法。

setTimeout是最简单、最可靠的方法。修补不属于您的页面时,这是一个很好的方法。

如果您想在下一个按钮出现时立即单击它,请减少超时时间,如果该按钮尚不存在,请设置一个新的超时时间。也没有必要依赖像 jQuery 这样的大依赖:

document.querySelector('[id="BA-SMSNY4E48EHGC__ACH__STANDARD_FUNDSRadioBtn"]').click();
const clickNext = () => {
  const btn = document.querySelector('[name="selectFiNext|standard"]');
  if (btn) btn.click();
  else setTimeout(clickNext, 50);
};
setTimeout(clickNext, 50);

如果你真的想避免轮询,你也可以在按钮的父级上使用 MutationObserver,但这会变得更加复杂。

如果按钮出现在网络请求之后,另一个可行的选项是监视网络请求何时完成,如果站点正在使用 jQuery,则使用 ajaxComplete,或者通过 monkeypatching window.XMLHttpRequest.

您需要将事件处理程序绑定到“单击”JavaScript 事件,或在元素上触发该事件。如下:

$(function(){
  $('[id="BA-SMSNY4E48EHGC__ACH__STANDARD_FUNDSRadioBtn"]').click(function(){
    $('[name="selectFiNext|standard"]').click();
  });

  $('[id="BA-SMSNY4E48EHGC__ACH__STANDARD_FUNDSRadioBtn"]').click();
});

以下代码片段将事件处理程序 click 附加到 ID 为 BA-SMSNY4E48EHGC__ACH__STANDARD_FUNDSRadioBtn 的元素,这将触发具有属性 name="selectFiNext|standard".

的元素的事件句柄 click

只是想分享一个更现代的方法,它与公认的答案相同,但在我看来更容易阅读:

// Converts set timeout from callback approach to promise approach
function AsyncTimeout(delay = 0) {
    return new Promise(function (resolve, reject) {
        setTimeout(resolve, delay);
    });
}

(async () => {
    // possibly, you might or might not want to awit a bit before you start
    // await AsyncTimeout(100);

    document.querySelector('[id="BA-SMSNY4E48EHGC__ACH__STANDARD_FUNDSRadioBtn"]').click();
    let btn = null;
    // safeguard to prevent endless loop if something goes wrong
    let iterations = 0;
    while (btn == null) {
        await AsyncTimeout(50);
        // try to assign the btn
        btn = document.querySelector('[name="selectFiNext|standard"]');
        // remember the iteration count
        ++iterations;
        // if we tried too many times, just give up
        if (iterations > 100) {
            throw new Error("Couldn't find the button to click");
        }
    }
    btn.click();
})();