Ajax/XMLHttpRequestは、古くから使われている技術ですが、すでにAjax/XMLHttpRequestの欠点や問題点を解消した fetch API がモダンブラウザに実装されているので、新しく覚えるあるいは新規にコードを起こす場合は、Ajax/XMLHttpRequestではなく、 fetch APIを使うべきです。
fetch APIを使うと、下記のようなawait async promiseを使って非同期な並行・並列処理をメソッドチェインで簡素に表現できます。
fetch.html:
fetch API
XMLHttpRequest
CGIなどの仕組みを使ってサーバからデータを取得するにはウェブページを遷移する必要がありますが、XMLHttpRequestを用いるとページの遷移なしに、動的かつ非同期にデータを取得することができます。このような技術はAjax (asynchronous JavaScript and XML) と呼ばれます。Ajaxを駆使するとJavaScriptを用いて[http://maps.google.co.jp/ Google マップ]のようなインタラクティブなウェブアプリケーションを構築することができます。
XMLHttpRequestはその名に反してXMLドキュメントでないデータもやり取りすることができます。また、HTTP以外にFTP通信も行うことができます2021年6月の時点でディフォルトでFTPスキームを（かつてのgopherのように）無効にするブラウザが増えつつある。https://blog.chromium.org/2020/09/chrome-86-improved-focus-highlighting.html（ローカルホストではローカルファイルも取得可能）。ただし、XMLHttpRequestを用いて通信できるのは同じドメインのサーバに限られるため、外部のサーバと通信をすることはできません。これを同一生成元ポリシー（どういつせいせいもとポリシー、''same origin policy''）といいます。
イベントリスナーによるイベントハンドリング:
const req = new XMLHttpRequest();
req.addEventListener("progress", (ev) => {
  if (ev.lengthComputable) {
    const percent = ev.loaded / ev.total * 100;
    // 進捗表示
    console.log("${percent}％転送しました。")
  }
  else {
    // 長さ不明
    console.log("転送中。")
  }
});
req.addEventListener("loadstart", (ev) => console.log("転送を開始しました。"));
req.addEventListener("load", (ev) => console.log("転送しました。"));
req.addEventListener("loadend", (ev) => console.log("転送が終了しました。"));
req.addEventListener("error", (ev) => console.log("ファイルの転送中にエラーが発生しました。"));
req.addEventListener("abort", (ev) => console.log("ユーザーが転送をキャンセルしました。"));
req.addEventListener("timeout", (ev) => console.log("転送がタイムアウトしました。"));
req.addEventListener("readystatechange", (ev) => {
    switch (req.readyState) {
    case XMLHttpRequest.UNSENT:
        console.log("UNSENT");
        break;
    case XMLHttpRequest.OPENED:
        console.log("OPENED");
        break;
    case XMLHttpRequest.HEADERS_RECEIVED:
        console.log("HEADERS_RECEIVED");
        break;
    case XMLHttpRequest.LOADIND:
        console.log("LOADIND");
        break;
    case XMLHttpRequest.DONE:
        const status = req.status;
        if (status === 0 || (status >= 200 && status < 400)) {
            console.log(req.responseText);
        }
        else {
            console.log(req.responseXML);
            console.log(req.responseText);
        }
        break;
    default :
        console.log(`${req.readyState} は仕様にないXMLHttpRequest.readyState`);
    }
});
req.open('GET', './example.xml', false);
req.send(null);
※ イベントリスナーは open() を呼び出す前に追加する必要があります（もし、そうしないのであれば progress イベントは発火しません）。
XMLHttpRequest.UNSENT
XMLHttpRequest.OPENED
XMLHttpRequest.HEADERS_RECEIVED
XMLHttpRequest.LOADING
XMLHttpRequest.DONE
XMLHttpRequest.arguments
XMLHttpRequest.caller
XMLHttpRequest.length
XMLHttpRequest.name
XMLHttpRequest.prototype.DONE
XMLHttpRequest.prototype.HEADERS_RECEIVED
XMLHttpRequest.prototype.LOADING
XMLHttpRequest.prototype.OPENED
XMLHttpRequest.prototype.UNSENT
XMLHttpRequest.prototype.abort
XMLHttpRequest.prototype.constructor()
XMLHttpRequest.prototype.getAllResponseHeaders
XMLHttpRequest.prototype.getResponseHeader
XMLHttpRequest.prototype.onreadystatechange
XMLHttpRequest.prototype.open
XMLHttpRequest.prototype.overrideMimeType
XMLHttpRequest.prototype.readyState
XMLHttpRequest.prototype.response
XMLHttpRequest.prototype.responseText
XMLHttpRequest.prototype.responseType
XMLHttpRequest.prototype.responseURL
XMLHttpRequest.prototype.responseXML
XMLHttpRequest.prototype.send
XMLHttpRequest.prototype.setRequestHeader
XMLHttpRequest.prototype.status
XMLHttpRequest.prototype.statusText
XMLHttpRequest.prototype.timeout
XMLHttpRequest.prototype.upload
XMLHttpRequest.prototype.withCredentials