7-1搜索提示|7_2二级菜单|7-4多个Ajax请求的并发执行

search

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>多个 Ajax 请求的并发执行</title>
<style>
/* css reset */
* {
padding: 0;
margin: 0;
}
li {
list-style: none;
}

/* menu */
.menu {
width: 100px;
background-color: rgba(0, 0, 0, 0.1);
margin: 10px;
}
.menu-item {
position: relative;
padding: 5px;
cursor: pointer;
}
.menu-content {
display: none;
position: absolute;
left: 100%;
top: 0;
width: 200px;
height: 100px;
padding: 0 5px;
background-color: rgba(0, 0, 0, 0.1);
}
.menu-item:hover {
background-color: rgba(0, 0, 0, 0.4);
}
.menu-item:hover .menu-content {
display: block;
}
.menu-loading {
margin: 45px 0 0 92px;
}

/* loading-page */
.loading-page {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1000;
background-color: #eee;
text-align: center;
}
.loading-img {
position: absolute;
top: 50%;
}
.ad img {
display: inline-block;
width: 25%;
}
.none {
display: none;
}
</style>
</head>
<body>
<div id="loading-page" class="loading-page">
<img class="loading-img" src="./loading.gif" alt="加载中" />
</div>

<div id="ad" class="ad"></div>

<ul id="menu" class="menu">
<!-- <li class="menu-item" data-key="hot" data-done="done">
<span>热门</span>
<div class="menu-content">
<p><img class="menu-loading" src="./loading.gif" alt="加载中" /></p>
</div>
</li> -->
</ul>
<script type="module">
import { getJSON } from './ajax/index.js';

const menuURL = 'https://www.imooc.com/api/mall-PC/index/menu';
const adURL = 'https://www.imooc.com/api/mall-PC/index/ad';

const loadingPageEl = document.getElementById('loading-page');
const adEl = document.getElementById('ad');
const menuEl = document.getElementById('menu');

const p1 = getJSON(menuURL)
.then(repsonse => {
// console.log(repsonse);

let html = '';

for (const item of repsonse.data) {
html += `
<li class="menu-item" data-key="${item.key}">
<span>${item.title}</span>
<div class="menu-content">
<p><img class="menu-loading" src="./loading.gif" alt="加载中" /></p>
</div>
</li>
`;
}

menuEl.innerHTML = html;

// [{key: "hot", title: "热门出发地", subTitles: Array(5)}]

// ...
})
.then(() => {
const items = menuEl.querySelectorAll('.menu-item');

for (const item of items) {
item.addEventListener(
'mouseenter',
() => {
// console.log(item.getAttribute('data-key'));

// IE11 开始支持
// console.log(item.dataset.key);

if (item.dataset.done === 'done') return;

getJSON(
`https://www.imooc.com/api/mall-PC/index/menu/${item.dataset.key}`
)
.then(repsonse => {
// console.log(repsonse);

// [{title: "内地热门城市", cities: Array(27)}]

item.dataset.done = 'done';

let html = '';

for (const item of repsonse.data) {
html += `<p>${item.title}</p>`;
}

item.querySelector('.menu-content').innerHTML = html;
})
.catch(err => {
console.log(err);
});
},
false
);
}
})
.catch(err => {
console.log(err);
});

const p2 = getJSON(adURL)
.then(response => {
// console.log(response);
// [{ url: 'http://alimc.img.imooc.com/class/' }];

let html = '';
for (const item of response.data) {
html += `<img src="${item.url}" alt="" />`;
}
adEl.innerHTML = html;
})
.catch(err => {
console.log(err);
});

Promise.all([p1, p2]).then(() => {
// loadingPageEl.style.display = 'none';

// IE10 开始支持
loadingPageEl.classList.add('none');
// loadingPageEl.classList.remove('none');
});
</script>
</body>
</html>

menu

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>多个 Ajax 请求的并发执行</title>
  <style>
    /* css reset */
    * {
      padding: 0;
      margin: 0;
    }
    li {
      list-style: none;
    }

    /* menu */
    .menu {
      width: 100px;
      background-color: rgba(0, 0, 0, 0.1);
      margin: 10px;
    }
    .menu-item {
      position: relative;
      padding: 5px;
      cursor: pointer;
    }
    .menu-content {
      display: none;
      position: absolute;
      left: 100%;
      top: 0;
      width: 200px;
      height: 100px;
      padding: 0 5px;
      background-color: rgba(0, 0, 0, 0.1);
    }
    .menu-item:hover {
      background-color: rgba(0, 0, 0, 0.4);
    }
    .menu-item:hover .menu-content {
      display: block;
    }
    .menu-loading {
      margin: 45px 0 0 92px;
    }

    /* loading-page */
    .loading-page {
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      z-index: 1000;
      background-color: #eee;
      text-align: center;
    }
    .loading-img {
      position: absolute;
      top: 50%;
    }
    .ad img {
      display: inline-block;
      width: 25%;
    }
    .none {
      display: none;
    }
  </style>
</head>
<body>
<div id="loading-page" class="loading-page">
  <img class="loading-img" src="./loading.gif" alt="加载中" />
</div>

<div id="ad" class="ad"></div>

<ul id="menu" class="menu">
  <!-- <li class="menu-item" data-key="hot" data-done="done">
    <span>热门</span>
    <div class="menu-content">
      <p><img class="menu-loading" src="./loading.gif" alt="加载中" /></p>
    </div>
  </li> -->
</ul>
<script type="module">
  import { getJSON } from './ajax/index.js';

  const menuURL = 'https://www.imooc.com/api/mall-PC/index/menu';
  const adURL = 'https://www.imooc.com/api/mall-PC/index/ad';

  const loadingPageEl = document.getElementById('loading-page');
  const adEl = document.getElementById('ad');
  const menuEl = document.getElementById('menu');

  const p1 = getJSON(menuURL)
          .then(repsonse => {
            // console.log(repsonse);

            let html = '';

            for (const item of repsonse.data) {
              html += `
              <li class="menu-item" data-key="${item.key}">
                <span>${item.title}</span>
                <div class="menu-content">
                  <p><img class="menu-loading" src="./loading.gif" alt="加载中" /></p>
                </div>
              </li>
            `;
            }

            menuEl.innerHTML = html;

            // [{key: "hot", title: "热门出发地", subTitles: Array(5)}]

            // ...
          })
          .then(() => {
            const items = menuEl.querySelectorAll('.menu-item');

            for (const item of items) {
              item.addEventListener(
                      'mouseenter',
                      () => {
                        // console.log(item.getAttribute('data-key'));

                        // IE11 开始支持
                        // console.log(item.dataset.key);

                        if (item.dataset.done === 'done') return;

                        getJSON(
                                `https://www.imooc.com/api/mall-PC/index/menu/${item.dataset.key}`
                        )
                                .then(repsonse => {
                                  // console.log(repsonse);

                                  // [{title: "内地热门城市", cities: Array(27)}]

                                  item.dataset.done = 'done';

                                  let html = '';

                                  for (const item of repsonse.data) {
                                    html += `<p>${item.title}</p>`;
                                  }

                                  item.querySelector('.menu-content').innerHTML = html;
                                })
                                .catch(err => {
                                  console.log(err);
                                });
                      },
                      false
              );
            }
          })
          .catch(err => {
            console.log(err);
          });

  const p2 = getJSON(adURL)
          .then(response => {
            // console.log(response);
            // [{ url: 'http://alimc.img.imooc.com/class/' }];

            let html = '';
            for (const item of response.data) {
              html += `<img src="${item.url}" alt="" />`;
            }
            adEl.innerHTML = html;
          })
          .catch(err => {
            console.log(err);
          });

  Promise.all([p1, p2]).then(() => {
    // loadingPageEl.style.display = 'none';

    // IE10 开始支持
    loadingPageEl.classList.add('none');
    // loadingPageEl.classList.remove('none');
  });
</script>
</body>
</html>

Ajaxask

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>多个 Ajax 请求的并发执行</title>
  <style>
    /* css reset */
    * {
      padding: 0;
      margin: 0;
    }
    li {
      list-style: none;
    }

    /* menu */
    .menu {
      width: 100px;
      background-color: rgba(0, 0, 0, 0.1);
      margin: 10px;
    }
    .menu-item {
      position: relative;
      padding: 5px;
      cursor: pointer;
    }
    .menu-content {
      display: none;
      position: absolute;
      left: 100%;
      top: 0;
      width: 200px;
      height: 100px;
      padding: 0 5px;
      background-color: rgba(0, 0, 0, 0.1);
    }
    .menu-item:hover {
      background-color: rgba(0, 0, 0, 0.4);
    }
    .menu-item:hover .menu-content {
      display: block;
    }
    .menu-loading {
      margin: 45px 0 0 92px;
    }

    /* loading-page */
    .loading-page {
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      z-index: 1000;
      background-color: #eee;
      text-align: center;
    }
    .loading-img {
      position: absolute;
      top: 50%;
    }
    .ad img {
      display: inline-block;
      width: 25%;
    }
    .none {
      display: none;
    }
  </style>
</head>
<body>
<div id="loading-page" class="loading-page">
  <img class="loading-img" src="./loading.gif" alt="加载中" />
</div>

<div id="ad" class="ad"></div>

<ul id="menu" class="menu">
  <!-- <li class="menu-item" data-key="hot" data-done="done">
    <span>热门</span>
    <div class="menu-content">
      <p><img class="menu-loading" src="./loading.gif" alt="加载中" /></p>
    </div>
  </li> -->
</ul>
<script type="module">
  import { getJSON } from './ajax/index.js';

  const menuURL = 'https://www.imooc.com/api/mall-PC/index/menu';
  const adURL = 'https://www.imooc.com/api/mall-PC/index/ad';

  const loadingPageEl = document.getElementById('loading-page');
  const adEl = document.getElementById('ad');
  const menuEl = document.getElementById('menu');

  const p1 = getJSON(menuURL)
          .then(repsonse => {
            // console.log(repsonse);

            let html = '';

            for (const item of repsonse.data) {
              html += `
              <li class="menu-item" data-key="${item.key}">
                <span>${item.title}</span>
                <div class="menu-content">
                  <p><img class="menu-loading" src="./loading.gif" alt="加载中" /></p>
                </div>
              </li>
            `;
            }

            menuEl.innerHTML = html;

            // [{key: "hot", title: "热门出发地", subTitles: Array(5)}]

            // ...
          })
          .then(() => {
            const items = menuEl.querySelectorAll('.menu-item');

            for (const item of items) {
              item.addEventListener(
                      'mouseenter',
                      () => {
                        // console.log(item.getAttribute('data-key'));

                        // IE11 开始支持
                        // console.log(item.dataset.key);

                        if (item.dataset.done === 'done') return;

                        getJSON(
                                `https://www.imooc.com/api/mall-PC/index/menu/${item.dataset.key}`
                        )
                                .then(repsonse => {
                                  // console.log(repsonse);

                                  // [{title: "内地热门城市", cities: Array(27)}]

                                  item.dataset.done = 'done';

                                  let html = '';

                                  for (const item of repsonse.data) {
                                    html += `<p>${item.title}</p>`;
                                  }

                                  item.querySelector('.menu-content').innerHTML = html;
                                })
                                .catch(err => {
                                  console.log(err);
                                });
                      },
                      false
              );
            }
          })
          .catch(err => {
            console.log(err);
          });

  const p2 = getJSON(adURL)
          .then(response => {
            // console.log(response);
            // [{ url: 'http://alimc.img.imooc.com/class/' }];

            let html = '';
            for (const item of response.data) {
              html += `<img src="${item.url}" alt="" />`;
            }
            adEl.innerHTML = html;
          })
          .catch(err => {
            console.log(err);
          });

  Promise.all([p1, p2]).then(() => {
    // loadingPageEl.style.display = 'none';

    // IE10 开始支持
    loadingPageEl.classList.add('none');
    // loadingPageEl.classList.remove('none');
  });
</script>
</body>
</html>

ajax.js

// 常量
import {
  HTTP_GET,
  CONTENT_TYPE_FORM_URLENCODED,
  CONTENT_TYPE_JSON
} from './constants.js';

// 工具函数
import { serialize, addURLData, serializeJSON } from './utils.js';

// 默认参数
import DEFAULTS from './defaults.js';

// Ajax 类
class Ajax {
  constructor(url, options) {
    this.url = url;
    this.options = Object.assign({}, DEFAULTS, options);

    // 初始化
    this.init();
  }

  // 初始化
  init() {
    const xhr = new XMLHttpRequest();

    this.xhr = xhr;

    // 绑定响应事件处理程序
    this.bindEvents();

    xhr.open(this.options.method, this.url + this.addParam(), true);

    // 设置 responseType
    this.setResponseType();

    // 设置跨域是否携带 cookie
    this.setCookie();

    // 设置超时
    this.setTimeout();

    // 发送请求
    this.sendData();
  }

  // 绑定响应事件处理程序
  bindEvents() {
    const xhr = this.xhr;

    const { success, httpCodeError, error, abort, timeout } = this.options;

    // load
    xhr.addEventListener(
      'load',
      () => {
        if (this.ok()) {
          success(xhr.response, xhr);
        } else {
          httpCodeError(xhr.status, xhr);
        }
      },
      false
    );

    // error
    // 当请求遇到错误时,将触发 error 事件
    xhr.addEventListener(
      'error',
      () => {
        error(xhr);
      },
      false
    );

    // abort
    xhr.addEventListener(
      'abort',
      () => {
        abort(xhr);
      },
      false
    );

    // timeout
    xhr.addEventListener(
      'timeout',
      () => {
        timeout(xhr);
      },
      false
    );
  }

  // 检测响应的 HTTP 状态码是否正常
  ok() {
    const xhr = this.xhr;
    return (xhr.status >= 200 && xhr.status < 300) || xhr.status === 304;
  }

  // 在地址上添加数据
  addParam() {
    const { params } = this.options;

    if (!params) return '';

    return addURLData(this.url, serialize(params));
  }

  // 设置 responseType
  setResponseType() {
    this.xhr.responseType = this.options.responseType;
  }

  // 设置跨域是否携带 cookie
  setCookie() {
    if (this.options.withCredentials) {
      this.xhr.withCredentials = true;
    }
  }

  // 设置超时
  setTimeout() {
    const { timeoutTime } = this.options;

    if (timeoutTime > 0) {
      this.xhr.timeout = timeoutTime;
    }
  }

  // 发送请求
  sendData() {
    const xhr = this.xhr;

    if (!this.isSendData()) {
      return xhr.send(null);
    }

    let resultData = null;
    const { data } = this.options;

    // 发送 FormData 格式的数据
    if (this.isFormData()) {
      resultData = data;
    } else if (this.isFormURLEncodedData()) {
      // 发送 application/x-www-form-urlencoded 格式的数据

      this.setContentType(CONTENT_TYPE_FORM_URLENCODED);
      resultData = serialize(data);
    } else if (this.isJSONData()) {
      // 发送 application/json 格式的数据

      this.setContentType(CONTENT_TYPE_JSON);
      resultData = serializeJSON(data);
    } else {
      // 发送其他格式的数据

      this.setContentType();
      resultData = data;
    }

    xhr.send(resultData);
  }

  // 是否需要使用 send 发送数据
  isSendData() {
    const { data, method } = this.options;

    if (!data) return false;

    if (method.toLowerCase() === HTTP_GET.toLowerCase()) return false;

    return true;
  }

  // 是否发送 FormData 格式的数据
  isFormData() {
    return this.options.data instanceof FormData;
  }

  // 是否发送 application/x-www-form-urlencoded 格式的数据
  isFormURLEncodedData() {
    return this.options.contentType
      .toLowerCase()
      .includes(CONTENT_TYPE_FORM_URLENCODED);
  }

  // 是否发送 application/json 格式的数据
  isJSONData() {
    return this.options.contentType.toLowerCase().includes(CONTENT_TYPE_JSON);
  }

  // 设置 Content-Type
  setContentType(contentType = this.options.contentType) {
    if (!contentType) return;

    this.xhr.setRequestHeader('Content-Type', contentType);
  }

  // 获取 XHR 对象
  getXHR() {
    return this.xhr;
  }
}

export default Ajax;

constants.js

// 常量
export const HTTP_GET = 'GET';
export const CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded';
export const CONTENT_TYPE_JSON = 'application/json';

export const ERROR_HTTP_CODE = 1;
export const ERROR_HTTP_CODE_TEXT = 'HTTP 状态码异常';
export const ERROR_REQUEST = 2;
export const ERROR_REQUEST_TEXT = '请求被阻止';
export const ERROR_TIMEOUT = 3;
export const ERROR_TIMEOUT_TEXT = '请求超时';
export const ERROR_ABORT = 4;
export const ERROR_ABORT_TEXT = '请求终止';

defaults.js

import Ajax from './ajax.js';
// 常量
import {
  ERROR_HTTP_CODE,
  ERROR_REQUEST,
  ERROR_TIMEOUT,
  ERROR_ABORT,
  ERROR_HTTP_CODE_TEXT,
  ERROR_REQUEST_TEXT,
  ERROR_TIMEOUT_TEXT,
  ERROR_ABORT_TEXT
} from './constants.js';

const ajax = (url, options) => {
  // return new Ajax(url, options).getXHR();
  let xhr;
  const p = new Promise((resolve, reject) => {
    xhr = new Ajax(url, {
      ...options,
      ...{
        success(response) {
          resolve(response);
        },
        httpCodeError(status) {
          reject({
            type: ERROR_HTTP_CODE,
            text: `${ERROR_HTTP_CODE_TEXT}: ${status}`
          });
        },
        error() {
          reject({
            type: ERROR_REQUEST,
            text: ERROR_REQUEST_TEXT
          });
        },
        abort() {
          reject({
            type: ERROR_ABORT,
            text: ERROR_ABORT_TEXT
          });
        },
        timeout() {
          reject({
            type: ERROR_TIMEOUT,
            text: ERROR_TIMEOUT_TEXT
          });
        }
      }
    }).getXHR();
  });

  p.xhr = xhr;
  p.ERROR_HTTP_CODE = ERROR_HTTP_CODE;
  p.ERROR_REQUEST = ERROR_REQUEST;
  p.ERROR_TIMEOUT = ERROR_TIMEOUT;
  p.ERROR_ABORT = ERROR_ABORT;

  return p;
};

const get = (url, options) => {
  return ajax(url, { ...options, method: 'GET' });
};

const getJSON = (url, options) => {
  return ajax(url, { ...options, method: 'GET', responseType: 'json' });
};

const post = (url, options) => {
  return ajax(url, { ...options, method: 'POST' });
};

export { ajax, get, getJSON, post };

utils.js

import Ajax from './ajax.js';
// 常量
import {
  ERROR_HTTP_CODE,
  ERROR_REQUEST,
  ERROR_TIMEOUT,
  ERROR_ABORT,
  ERROR_HTTP_CODE_TEXT,
  ERROR_REQUEST_TEXT,
  ERROR_TIMEOUT_TEXT,
  ERROR_ABORT_TEXT
} from './constants.js';

const ajax = (url, options) => {
  // return new Ajax(url, options).getXHR();
  let xhr;
  const p = new Promise((resolve, reject) => {
    xhr = new Ajax(url, {
      ...options,
      ...{
        success(response) {
          resolve(response);
        },
        httpCodeError(status) {
          reject({
            type: ERROR_HTTP_CODE,
            text: `${ERROR_HTTP_CODE_TEXT}: ${status}`
          });
        },
        error() {
          reject({
            type: ERROR_REQUEST,
            text: ERROR_REQUEST_TEXT
          });
        },
        abort() {
          reject({
            type: ERROR_ABORT,
            text: ERROR_ABORT_TEXT
          });
        },
        timeout() {
          reject({
            type: ERROR_TIMEOUT,
            text: ERROR_TIMEOUT_TEXT
          });
        }
      }
    }).getXHR();
  });

  p.xhr = xhr;
  p.ERROR_HTTP_CODE = ERROR_HTTP_CODE;
  p.ERROR_REQUEST = ERROR_REQUEST;
  p.ERROR_TIMEOUT = ERROR_TIMEOUT;
  p.ERROR_ABORT = ERROR_ABORT;

  return p;
};

const get = (url, options) => {
  return ajax(url, { ...options, method: 'GET' });
};

const getJSON = (url, options) => {
  return ajax(url, { ...options, method: 'GET', responseType: 'json' });
};

const post = (url, options) => {
  return ajax(url, { ...options, method: 'POST' });
};

export { ajax, get, getJSON, post };

 

posted @ 2023-03-30 17:11  ja不会va  阅读(56)  评论(0编辑  收藏  举报