专业的编程技术博客社区

网站首页 > 博客文章 正文

JavaScript—Promise 入门(javascript怎么入门)

baijin 2024-10-11 10:47:46 博客文章 10 ℃ 0 评论

Promise在中文中被表示成“期约”,下文均用原词Promise

很多时候请求在程序中或网页上进行操作,但请求的结果不能立即用于进一步处理。 在这种情况下,操作被认为是异步的。 为了更顺利地处理这种特定情况,JavaScript 有一个称为 的对象 Promise ,它表示异步操作的最终完成或失败,并为程序员提供处理异步操作和数据的方法。

问题

在深入研究 Promise 及其用途之前,最好先了解它们帮助解决的问题。 通常在 JavaScript 中,一个函数在返回自己的结果之前依赖于另一个函数的结果。 例如,考虑一组复杂的数学运算,它们一个接一个地执行,并且在执行下一个运算之前取决于前一个运算的结果。

const add = (n1, n2) => {
  return n1 + n2;
};const square = (n) => {
  return n * n;
};let v1 = add(5, 8);
let v2 = square(v1);
console.log(v2); // 169

此代码按从上到下的顺序执行。 每个函数都能够在使用结果的下一个函数执行之前返回结果。 但是,在某些情况下,函数在返回结果之前需要一些时间才能完成,而 JavaScript 在执行代码时不会等待。

const add = (n1, n2) => {
  setTimeout(() => {
    return n1 + n2;
  }, 2000);
};const square = (n) => {
  return n * n;
};let result = add(5, 8);
console.log(square(result)); // NaN

上面代码的不同之处在于 add函数在完成操作并返回结果之前有 2 秒的延迟。 到发生时,其余代码已经运行。 在第二个函数执行的那一刻,变量 v1有一个价值 undefined,当传入 square函数返回 NaN,在第一个函数可以返回其计算值之前输出。

回调解决问题

在 ES6 中将 promise 添加到 JavaScript 之前,处理异步操作的最佳方法是使用回调。 回调基本上是一个函数,它作为参数传递给另一个函数,然后在第一个函数体内调用。 这样做的一个常见原因是处理异步数据检索——程序的进展取决于数据,这些数据可能需要一些时间才能返回并提供给程序的下一部分。 一个典型的例子是异步等待来自 API 的数据,而程序的另一部分需要该数据才能继续。

例如,上面的例子目前无法处理 square函数在调用之前 add功能已经完成。 为了解决这个问题, square函数可以作为回调调用 add函数,像这样:

const add = (n1, n2, callback) => {
  setTimeout(() => {
    let calculation = n1 + n2;
    callback(calculation);
  }, 2000);
};const square = (n) => {
  return n * n;
};add(5, 8, (result) => {
  console.log(square(result));
});

上面的例子执行 add异步函数,然后传递结果 add功能到 square功能。 这 square函数然后使用结果 add函数来计算结果的平方。 在这种情况下,即使有 2 秒的延迟, square函数能够使用结果 add函数,因为回调取决于结果 add功能。

上面这个简单的例子并不难理解。 但是,一个操作可能需要几个步骤才能完成,这将需要多个回调。 例如,考虑以下代码:

const add = (n1, n2, callback) => {
  setTimeout(() => {
    let result = n1 + n2;
    callback(result);
  }, 2000);
};const multiply = (n1, n2, callback) => {
  setTimeout(() => {
    let result = n1 * n2;
    callback(result);
  }, 2000);
};const subtract = (n1, n2, callback) => {
  setTimeout(() => {
    let result = n1 - n2;
    callback(result);
  }, 2000);
});const square = (n) => {
  return n * n;
};add(5, 8, (result) => {
  multiply(result, 5, (result) => {
    subtract(result, 8, (result) => {
      console.log(square(result));
    });
  });
});

虽然这个例子看起来并不太复杂,但它确实展示了回调模式是如何被深度嵌套的,并且任务比上面显示的更复杂,理解正在发生的事情会变得非常困难。 幸运的是,JavaScript 的开发人员认识到了这个问题并提出了解决方案。

使用 Promise 改进回调

如上所述,回调的问题在于它们可能变得复杂且难以维护和/或理解。 相互嵌套的多个回调很快就会变得难以管理,有时被称为回调地狱 。 此外,当异步请求未成功完成时,回调不提供任何内置的错误处理。 此功能必须由开发人员添加。

的引入 Promise 对象 有助于解决这些问题,并提供一种更优雅的异步操作处理方式。 Promise 表示异步操作的最终完成或失败,并为程序员提供处理异步操作和数据的方法。

Promise 背后的核心思想是,当异步操作正在进行时,它将返回一个中间值,可用于跟踪操作的进度。 一旦操作完成,Promise 要么解析为最终值,要么不解析。 该值可用于确定操作的成功或失败。

Promise 的核心概念是 Promise 可以经历的不同状态:

  • 待定 - Promise 处于初始状态,既未解决(已完成)也未拒绝
  • 已完成(已解决)——promise 操作已成功完成
  • 拒绝 - Promise 操作失败

进入resolved 或rejected 选项将触发其关联的处理程序,这些处理程序通过调用Promise 进行处理 then方法。

使用Promise

使用 可以通过使用预先存在的 来完成,通常以外部库或 API 的形式,可以作为 或者通过 创建 Promise Promise Promise 新的 Promise 使用, 使用构造函数 。 通过从头开始创建Promise ,可以了解Promise 在内部做什么。

以下示例显示了如何创建新Promise 的基础知识。 一个Promise 期望一个 executor包含自定义代码以指示Promise 如何解决或拒绝Promise 的函数。 执行器函数包括解析函数和拒绝函数的签名,可用于传递由相应的解析和拒绝函数处理的值。

const myPromise = new Promise((resolve, reject) => {
  resolve('promise is resolved');
});myPromise.then((result) => {
  console.log(result);
});

一个更复杂的例子展示了如何添加控制流,以根据执行程序函数内的逻辑操作的结果来确定是否使用解析或拒绝函数。

const additionPromise = (number1, number2) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (typeof number1 === 'number' && typeof number2 === 'number') {
        let result = number1 + number2;
        resolve(result);
      } else {
        reject('Please use numbers');
      }
    }, 2000);
  });
};additionPromise(5, 7)
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
    console.error(error);
  })
  .finally(() => {
    console.log('promise completed');
  });// 12
// promise completedadditionPromise(5, 'hello')
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
    console.error(error);
  })
  .finally(() => {
    console.log('promise completed');
  });// Please use numbers
// promise completed

上面的 Promise 展示了几个不同的概念。 一、功能 additionPromise是一个常规函数,它接受两个参数并返回一个Promise 。 Promise 由一个执行程序函数组成,该函数包括一个解析和拒绝函数处理程序。 执行器还包含一个 setTimeout函数来演示 Promise 的异步性质。 如果传递的参数对于逻辑运算返回 true,则将数字相加并将结果变量传递给解析函数,该函数可由 then方法。

如果逻辑运算返回 false,则调用拒绝函数,传入一个字符串值。 处理这种情况的方式是调用 catch期约的方法。 如果调用reject函数,promise会绕过所有resolve(包括chained) then方法和使用 catch方法。 最后,一个可选的 finally方法可以调用。 无论 Promise 是解决还是拒绝,都会调用此方法。

链式 Promise

如上所述,Promise可以链接在一起,这允许在返回最终结果之前处理包含多个进程的多个 Promise。

const additionPromise = (number1, number2) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (typeof number1 === 'number' && typeof number2 === 'number') {
        let result = number1 + number2;
        resolve(result);
      } else {
        reject('Please use numbers');
      }
    }, 2000);
  });
};const squarePromise = (number) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (typeof number === 'number') {
        let result = number * number;
        resolve(result);
      } else {
        reject('Please use a valid number');
      }
    }, 2000);
  });
};additionPromise(2, 4)
  .then((result) => {
    return squarePromise(result);
  })
  .then((result) => {
    console.log(`final result: ${result}`);
  })
  .catch((error) => {
    console.log(error);
  })
  .finally(() => {
    console.log('promise operation completed');
  });// final result: 36
// promise operation completed

上面的例子展示了如何使用多个promise,每个promise都解析返回一个结果,promise可以使用该结果单步执行异步操作。

结论

如果遇到 Promise 的唯一方法是尝试使用它们,则很难理解 Promise。 通过创建Promise并了解它们的组成方式,可以更容易地了解使用它们的最佳步骤。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表