Promise 基础:异步编程的救星

在 JavaScript 开发中,异步编程是一个常见的需求,尤其是在处理网络请求、文件操作或定时任务时。然而,传统的回调函数方式很容易导致代码嵌套过深,形成"回调地狱",使得代码难以阅读和维护。为了解决这一问题,Promise A+ 规范应运而生,并在 ES6 中得到了实现。

一、什么是 Promise

Promise 是一种用于处理异步操作的对象,它代表了一个可能还未完成的操作。Promise 有三个状态:

  1. Pending(挂起):初始状态,既不是成功,也不是失败。
  2. Fulfilled(完成):操作成功完成。
  3. Rejected(失败):操作失败。

Promise 的状态转换是单向的,一旦从 Pending 转变为 Fulfilled 或 Rejected,状态就固定下来,无法再改变。

javascript 复制代码
const pro1 = new Promise((resolve, reject) => {
  console.log('任务开始');
  resolve(1);
  reject(2); // 无效
  resolve(3); // 无效
  console.log('任务结束');
});

console.log(pro1);

pro1.then(
  (data) => {
    console.log(data); // 1
  },
  (reason) => {
    console.log(reason);
  }
);

在这个例子中,resolve(1) 将 Promise 的状态从 Pending 转变为 Fulfilled,并传递了值 1。后续的 reject(2)resolve(3) 都是无效的,因为 Promise 的状态已经固定为 Fulfilled。

二、创建 Promise

Promise 的构造函数接受一个执行器函数,该函数会立即被调用,并且可以调用 resolvereject 来改变 Promise 的状态。以下是一个简单的例子:

javascript 复制代码
const pro = new Promise((resolve, reject) => {
  // 模拟异步操作
  setTimeout(() => {
    const success = true; // 假设这是异步操作的结果
    if (success) {
      resolve('操作成功');
    } else {
      reject('操作失败');
    }
  }, 1000);
});

pro.then(
  (data) => {
    console.log(data); // 操作成功
  },
  (reason) => {
    console.log(reason); // 操作失败
  }
);

在这个例子中,我们创建了一个 Promise 对象 pro,并在 1 秒后通过 resolvereject 改变了它的状态。then 方法用于指定任务完成或失败后的处理函数。

三、Promise 的实际应用

1. 延迟操作

假设我们需要一个函数来延迟一段指定的时间,然后执行某个操作。使用 Promise 可以轻松实现:

javascript 复制代码
function delay(duration) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, duration);
  });
}

delay(1000).then(() => {
  console.log('finish');
});

在这个例子中,delay 函数返回一个 Promise 对象,该对象在指定的时间后通过 resolve 完成。

2. 加载图片

加载图片是一个常见的异步操作,我们可以使用 Promise 来处理图片的加载成功或失败:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div class="container"></div>
  <p class="label"></p>
  <script>
    function createImage(imgUrl) {
      return new Promise((resolve, reject) => {
        const img = document.createElement('img');
        img.src = imgUrl;
        img.onload = () => {
          resolve(img);
        };
        img.onerror = (e) => {
          reject(e);
        };
      });
    }

    const url1 = 'myImage.jpg';
    createImage(url1).then(
      (img) => {
        const p = document.querySelector('.label');
        p.innerHTML = `${img.width} * ${img.height}`;
        const div = document.querySelector('.container');
        div.appendChild(img);
      },
      (reason) => {
        console.log(reason);
      }
    );
  </script>
</body>
</html>

在这个例子中,createImage 函数返回一个 Promise 对象,该对象在图片加载成功时通过 resolve 完成,并返回图片 DOM 元素;在图片加载失败时通过 reject 失败,并返回错误原因。

3. 加载远程数据

假设我们需要从远程服务器加载数据,可以使用 Promise 来处理:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <select id="selProvince"></select>
  <script>
    function getProvinces() {
      return fetch('https://study.duyiedu.com/api/citylist')
        .then((resp) => resp.json())
        .then((resp) => resp.data)
        .then((resp) =>
          resp.map((it) => ({ value: it.value, label: it.label }))
        );
    }

    getProvinces().then(
      (ps) => {
        const html = ps
          .map((p) => `<option value="${p.value}">${p.label}</option>`)
          .join('');
        const selProvince = document.getElementById('selProvince');
        selProvince.innerHTML = html;
      },
      (reason) => {
        console.log(reason);
      }
    );
  </script>
</body>
</html>

在这个例子中,getProvinces 函数返回一个 Promise 对象,该对象在成功加载数据时通过 resolve 完成,并返回省份数组;在加载失败时通过 reject 失败,并返回错误原因。

总结

Promise 是一种强大的工具,用于处理异步操作。它通过标准化的接口,使得异步代码更加清晰、简洁、统一。通过本文的介绍,希望你能够更好地理解和使用 Promise,从而在实际开发中避免回调地狱的困扰。

相关推荐
_r0bin_2 小时前
前端面试准备-7
开发语言·前端·javascript·fetch·跨域·class
IT瘾君2 小时前
JavaWeb:前端工程化-Vue
前端·javascript·vue.js
zhang98800002 小时前
JavaScript 核心原理深度解析-不停留于表面的VUE等的使用!
开发语言·javascript·vue.js
potender2 小时前
前端框架Vue
前端·vue.js·前端框架
站在风口的猪11083 小时前
《前端面试题:CSS预处理器(Sass、Less等)》
前端·css·html·less·css3·sass·html5
程序员的世界你不懂3 小时前
(9)-Fiddler抓包-Fiddler如何设置捕获Https会话
前端·https·fiddler
MoFe13 小时前
【.net core】天地图坐标转换为高德地图坐标(WGS84 坐标转 GCJ02 坐标)
java·前端·.netcore
去旅行、在路上4 小时前
chrome使用手机调试触屏web
前端·chrome
Aphasia3114 小时前
模式验证库——zod
前端·react.js
lexiangqicheng5 小时前
es6+和css3新增的特性有哪些
前端·es6·css3