学会Promise,看这里!!!

一个兜兜转转,从"北深"回到三线城市的小码农,热爱生活,热爱技术,在这里和大家分享一个技术人员的点点滴滴。欢迎大家关注我的微信公众号:果冻想

前言

众所周知,在JavaScript的世界中,代码都是单线程执行的。由于这个原因,JavaScript中的耗时操作,如网络操作、浏览器事件等,都需要异步执行。这也导致在JavaScript中异步操作是非常频繁且常见的。

异步:在执行某些耗时、不会立即返回结果的操作时,不会阻塞后面的操作,一旦该耗时操作完成时,立即通知需要调用其结果的函数来做后续处理。

而这种通知需要调用其结果的函数来做后续处理,一般都是通过回调的方式实现的。但是为了实现某些逻辑经常会写出层层嵌套的回调函数,如果嵌套过多,会极大影响代码可读性和逻辑,就会出现"回调地狱"。比如说你要把一个函数 A作为回调函数,但是该函数又接受一个函数B作为参数,甚至B还接受C作为参数使用,就这样层层嵌套,人称之为回调地狱,代码阅读性非常差。比如:

javascript 复制代码
var sayhello = function (name, callback) {
  setTimeout(function () {
    console.log(name);
    callback();
  }, 1000);
}

sayhello("first", function () {
  sayhello("second", function () {
    sayhello("third", function () {
      console.log("end");
    });
  });
});

//输出: first second third  end

而Promise作为一种可以优雅的解决这种"回调地狱"问题的方案,在实际开发中大面积使用,具有非常不错的效果。平时开发中,自己也经常看到这种情况,但是每次都是按照模板套路去编写业务代码,至于Promise是怎么使用的,根本没有学习总结过,导致自己总是一头雾水。这次,就认真的总结一下,同样的,只看样式,不究原理。待日后武义精益了,再来深挖掘。

Promise简介

Promise是异步编程的一种解决方案,是一个对象,可以获取异步操作的消息,大大改善了异步编程的困难,避免了回调地狱,比传统的解决方案回调函数和事件更合理和更强大。

从语法上讲,Promise是一个对象,它可以获取异步操作的消息。提供了一个统一的API,各种异步操作都可以用同样的方法进行处理。

首先了解下Promise的几个要点知识:

  1. 语法上,promise是一个构造函数;功能上,promise对象用来封装一个异步操作并获取执行的结果;
  2. 它有三种状态,pending(打包中,创建promise对象后的状态)、resolved(成功)、rejected(失败);
  3. 一个promise对象只能改变一次状态,成功或者失败后都会返回结果数据;
  4. 成功的结果数据一般称为value,失败的结果数据为reason。

Promise的实例有两个过程:

  1. pending > fulfilled :Resolved
  2. pending > rejected :Rejected

Promise基本用法

创建Promise对象

Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。Promise构造函数接收一个函数作为参数,该函数的两个参数分别是resolvereject

Promise创建时,会传给promise一个称为excutor执行器的函数。这个excutor我们可以理解为生产者的生产过程函数。这个函数含有两个参数resolve和reject,这俩参数也同样是函数,用来传递异步操作的结果。

javascript 复制代码
let promise = new Promise(function(resolve, reject) {
  // executor 
})

重点说明:

  1. 在Promise对象创建时,excutor会立即执行;
  2. 在resolve和reject是JS引擎自动创建的函数,我们无需自己创建,只需将其作为参数传入就好。

then()用法

Promise 实例生成以后,可以用 then 为实例添加状态改变时的回调函数。then方法可以接收两个回调函数作为参数,第一个回调函数是Promise对象的状态改变为resoved的调用,第二个回调函数是Promise对象的状态变为rejected的调用。其中第二个参数可以省略。

javascript 复制代码
function getData() {
    return new Promise(function(resolve, reject) {
        var obj = {num : 0};
        setTimeout(function(){ // 模拟异步请求
            obj.num = Math.random();
            resolve(obj);
        }, 1000);
    });
}

getData().then(function(obj){
    console.log(obj.num);
});

getData函数返回一个promise实例,使用then为它指定一个Resolved状态的回调函数,异步请求中传给resolve的值,将作为回调函数中的参数。当异步请求成功之后,回调函数变会执行输出对应的值。

假设异步请求失败了怎么办? then其实还可以指定第二个可选的参数,即Rejected状态的回调函数。

lua 复制代码
getData().then(function(obj){
    console.log(obj.num);
}, function(error){
    console.log(error);
});

catch()用法

在上述例子中,异步请求成功后,第一个回调函数会执行,如果失败了,第二个回调函数便会执行。

其实我们还可以使用catch指定错误时的回调,catch调用其实等同于使用then(undefined, function)。上述代码和以下代码是同样的效果。

scss 复制代码
getData().then(function(obj){
    console.log(obj.num);
}).catch(e){
    console.log(e);
}

all()用法

all方法可以完成并进行任务,它接收的是一个数组,数组的每一项都是Promise对象。当数组中所有的Promise状态都达到resolved的时候,all方法的状态就会变成resolved,如果有一个状态变成了rejected。那么all方法的状态就会变成rejected。

javascript 复制代码
let promise1 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(1);
    }, 1000);
});

let promise2 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(2);
    }, 2000);
});

let promise3 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(3);
    }, 3000);
});

Promise.all([promise1, promise2, promise3]).then(function(res) {
    console.log(res); // 输出 [1, 2, 3]
});

race()用法

race方法和all一样,接收的参数是一个每项都是Promise的数组,但是与all不同的是,当最先执行完的事件执行完之后,就直接返回该promise对象的值。

race的实际作用:当要做一件事,超过长时间就不做了,可以用这个方法来解决。

javascript 复制代码
let promise1 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(1);
    }, 1000);
});

let promise2 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(2);
    }, 2000);
});

let promise3 = new Promise(function(resolve, reject) {
    setTimeout(function(){
        resolve(3);
    }, 3000);
});

Promise.race([promise1, promise2, promise3]).then(function(res) {
    console.log(res); // 输出 1
});

finally()用法

finally方法用于指定不管Promise对象最后状态如何,都会执行的操作。finally方法的回调函数不接受任何参数,这意味着没有办法知道前面的Promise状态到底是fulfilled还是rejected。

总结

由于自己对这个知识点掌握的少,所以这篇文章总结的很基础,希望对入门的选手有一个帮助。

一个兜兜转转,从"北深"回到三线城市的小码农,热爱生活,热爱技术,在这里和大家分享一个技术人员的点点滴滴。欢迎大家关注我的微信公众号:果冻想

相关推荐
ZC跨境爬虫6 小时前
跟着 MDN 学JavaScript day_9:字符串方法实战挑战与解题思路
开发语言·前端·javascript
hewins6 小时前
NestJS 从入门到精通
javascript
柒和远方6 小时前
LeetCode 452. 用最少数量的箭引爆气球 —— 区间贪心经典:排序 + 扫描一箭穿心
javascript·python·算法
小小龙学IT6 小时前
Drizzle ORM:TypeScript 生态中冉冉升起的数据库工具链引言
javascript·数据库·typescript
旺王雪饼 www8 小时前
localStorage 和 sessionStorage区别与联系
服务器·前端·javascript
এ慕ོ冬℘゜8 小时前
【双月日期范围选择器】博客(可直接交作业 / 上线)
前端·javascript·交互·jquery
VidDown8 小时前
VidDown 使用介绍:一个免费、本地化的在线工具集
javascript·编辑器·音视频·视频编解码·视频
小牛itbull9 小时前
告别传统主题开发!ReactPress Theme Starter —— 用 Next.js 15 构建现代化无头博客
javascript·cms·react·wordpress·nextjs·reactpress·blog-theme
深蓝电商API9 小时前
逆向工程入门:从Chrome DevTools到JS混淆还原
前端·javascript·chrome·爬虫·chrome devtools
nap-joker9 小时前
使用n8n+飞书搭建自动推送新闻机器人
javascript·json·飞书·工作流·n8n·36氪新闻向客户端推送