【ES6】Promise 使用

文章目录

一、含义

1、是什么

Promise 是异步编程的一种解决方案

2、特点

Promise对象有以下两个特点:

1、对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)

2、一旦状态改变,就不会再变,任何时候都可以得到这个结果

二、用法

1、基本使用

ES6 规定,Promise对象是一个构造函数,用来生成Promise实例

代码示例:

js 复制代码
const promise = new Promise(function (resolve, reject) {
  // ... some code
  console.log('这里的代码是同步代码,会立即执行~');

  let flag = true;
  // let flag = false;
  if (flag) {
    resolve(true);
  } else {
    reject(false);
  }
});

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数:

js 复制代码
promise.then(
  function (value) {
  	// success
  	// Promise对象的状态变为resolved时调用
  },
  function (error) {
    // failure
    // Promise对象的状态变为rejected时调用
  }
);

示例:timeout

js 复制代码
function timeout(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('done');
    }, time);
  });
}

timeout(2000).then((value) => {
  console.log(value);
});

示例:异步加载图片

js 复制代码
function loadImageAsync(url) {
  return new Promise(function(resolve, reject) {
    const image = new Image();

    image.onload = function() {
      resolve(image);
    };

    image.onerror = function() {
      reject(new Error('Could not load image at ' + url));
    };

    image.src = url;
  });
}

2、resolve函数和reject函数带有参数

如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。

2.1 resolve

2.1.1 参数为正常值的情况
js 复制代码
const p = new Promise((resolve, reject) => {
  resolve('hello');
});

p.then((value) => {
  console.log(value); // hello
});
2.1.2 参数为Promise 实例的情况

当一个 Promise 实例在 resolve 方法中返回另一个 Promise 实例时,当前 Promise 的最终状态将由内部 Promise 实例的状态决定

如下示例:

p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态

如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行

js 复制代码
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('这是p1的resolve');
    // reject('这是p1的reject');
  }, 1000);
});

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    // p2 resolve传递 p1 实例
    resolve(p1);
  }, 1000);
});

p2.then((value) => {
  console.log('resolve--', value); // resolve--这是p1的resolve
}).catch((error) => {
  console.log('reject--', error);
});

2.2reject

reject函数的参数通常是Error对象的实例,表示抛出的错误

js 复制代码
const p = new Promise((resolve, reject) => {
  reject(new Error('出错了'));
});

p.catch((error) => {
  console.log('报错', error); // 报错Error{}
});

注意,调用resolve或reject并不会终结 Promise 的参数函数的执行。

js 复制代码
new Promise((resolve, reject) => {
  resolve(1);
  console.log(2); // 这里仍然会执行
}).then(r => {
  console.log(r);
});
// 2
// 1

3、Promise.prototype.then()

(1)then方法参数:

  • 第一个参数是 resolved 状态的回调函数(可选的)
  • 第二个参数是 rejected 状态的回调函数(可选的)

(2)then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例),因此可以采用链式写法

js 复制代码
getJSON("/posts.json").then(function(json) {
  return json.post;
}).then(function(post) {
  // ...
});

(3)当前then里面的回调函数返回的还是一个Promise对象(即有异步操作)时,这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用

js 复制代码
function getCount(count) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(count + 1);
    }, 2000);
  });
}

getCount(1)
  .then((val) => {
    console.log(val); // 2
    // 返回的还是一个Promise对象
    return getCount(val);
  })
  .then((val) => {
    console.log(val); // 3
  });

4、Promise.prototype.catch()

(1)Promise.prototype.catch()方法是.then(null, rejection).then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

js 复制代码
getJSON('/posts.json').then(function(posts) {
  // ...
}).catch(function(error) {
  // 处理 getJSON 和 前一个回调函数运行时发生的错误
  console.log('发生错误!', error);
});

(2)如果 Promise 状态已经变成resolved,再抛出错误是无效的。

js 复制代码
const promise = new Promise(function(resolve, reject) {
  resolve('ok');
  throw new Error('test'); // 无效
});
promise
  .then(function(value) { console.log(value) })
  .catch(function(error) { console.log(error) });
// ok

(3)Promise 对象的错误具有"冒泡"性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。

js 复制代码
getJSON('/post/1.json').then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // some code
}).catch(function(error) {
  // 处理前面三个Promise产生的错误
});

5、Promise.prototype.finally()

finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作

js 复制代码
promise
	.then(result => {···})
	.catch(error => {···})
	.finally(() => {···});

6、Promise.all()

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例

js 复制代码
const p = Promise.all([p1, p2, p3]); // p1、p2、p3都是 Promise 实例

p的状态由p1、p2、p3决定,分成两种情况:

(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数

示例:

js 复制代码
const p1 = new Promise(function (resolve, reject) {
  resolve(1);
});
const p2 = new Promise(function (resolve, reject) {
  resolve(2);
});
const p3 = new Promise(function (resolve, reject) {
  resolve(3);
});

const p = Promise.all([p1, p2, p3]);
p.then((list) => {
  console.log(list); // [1, 2, 3]
});

7、Promise.resolve()

将现有对象转为 Promise 对象

js 复制代码
Promise.resolve('foo')

等价于:

js 复制代码
new Promise(resolve => resolve('foo'))

8、Promise.reject()

Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected

js 复制代码
const p = Promise.reject('出错了');

等同于

js 复制代码
const p = new Promise((resolve, reject) => reject('出错了'))

三、练习题

1、第1题

js 复制代码
new Promise((resolve, reject) => {
  console.log(1);
  resolve();
})
  .then(() => {
    console.log(2);

    return new Promise((resove) => {
      console.log(4)
      resove();
    })
      .then(() => {
        console.log(5);
      })
      .then(() => {
        console.log(6);
      });
  })
  .then(() => {
    console.log(3);
  });

解析:

(1)外部第一个 new Promise 执行,执行完 resolve ,然后执行外部第一个 then

(2)外部第一个 then 方法里面 return 一个 Promise,这个 return 代表 外部的第二个 then 的执行需要等待 return 之后的结果

(3)执行完内部两个 then 之后,再执行 外部的第二个 then

2、第2题

注意:和第一题相差一个 return

js 复制代码
// 外部 promise
new Promise((resolve, reject) => {
  console.log(1);
  resolve();
})
  .then(() => {
    // 外部第一个 then
    console.log(2);
	
	// 内部 promise
    new Promise((resove) => {
      console.log(4);
      resove();
    })
      .then(() => {
      	// 内部第一个then
        console.log(5);
      })
      .then(() => {
      	// 内部第二个then
        console.log(6);
      });
  })
  .then(() => {
    // 外部第二个then
    console.log(3);
  });

解析:

重点: 下一个 then 的注册,需要等待上一个 then 的同步代码执行完成

执行顺序:

  1. 外部的 promise 立即执行,打印1;外部 promise 进行 resolve 后,执行外部第一个 then 的注册,外部第二个 then 进入等待状态
  2. 执行外部第一个 then, 打印2 ;立即执行内部的 promise 打印4;进行 resolve后,内部的第一个 then 注册,内部的第二个 then 进入等待状态;此时外部的第一个 then 的同步操作已经完成,然后开始注册外部第二个 then
  3. 执行内部第一个 then (因为内部第一个then是比外部第一个then先注册的),打印5,然后注册内部第二个 then;
  4. 执行外部第二个 then,打印3
  5. 执行内部第二个 then,打印6

所以最终的顺序:

js 复制代码
1
2
4
5
3
6

3、第3题

注意:内部第二个then不是链式调用

js 复制代码
// 外部 promise
new Promise((resolve, reject) => {
  console.log(1);
  resolve();
})
  .then(() => {
  	// 外部第一个 then
    console.log(2);
    
	// 内部 promise
    let p = new Promise((resolve, reject) => {
      console.log(4);
      resolve();
    });
    // 内部第一个then
    p.then(() => {
      console.log(5);
    });
    // 内部第二个then,注意这里不是链式调用,这里是跟内部第一个then是同步注册的
    p.then(() => {
      console.log(6);
    });
  })
  .then(() => {
  	// 外部第二个 then
    console.log(3);
  });

解析:

执行内部的 Promise 的 resolve 执行之后,两个同步 p.then 是两个执行代码语句,都是同步执行,自然是会同步注册完。

输出结果:

js 复制代码
1
2
4
5
6
3

4、第4题

js 复制代码
let p = new Promise((resolve, reject) => {
  console.log(1);
  resolve();
});

p.then(() => {
  console.log(2);

  new Promise((resolve, reject) => {
    console.log(3);
    resolve();
  })
    .then(() => {
      console.log(5);
    })
    .then(() => {
      console.log(6);
    });
});

p.then(() => {
  console.log(4);
});

解析:

外部的注册采用了非链式调用的写法,因此外部的 p.then 是并列同步注册的

内部的第一个 then 注册之后,就开始执行外部的第二个 then 了。然后再依次执行内部的第一个 then ,内部的第二个 then

5、第5题

js 复制代码
new Promise((resolve, reject) => {
  console.log(1);
  resolve();
})
  .then(() => {
    console.log(2);

    new Promise((resolve, reject) => {
      console.log(4);
      resolve();
    })
      .then(() => {
        console.log(5);
      })
      .then(() => {
        console.log(6);
      });
      
    return new Promise((resolve, reject) => {
      console.log(7);
      resolve();
    })
      .then(() => {
        console.log(8);
      })
      .then(() => {
        console.log(9);
      });
  })

  .then(() => {
    console.log(3);
  });

解析:

核心:外部的第二个 then ,依赖于内部的 return 的执行结果,所以会等待 return 执行完成

最终输出:

js 复制代码
1
2
4
7
5
8
6
9
3
相关推荐
恋猫de小郭1 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅9 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅9 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment9 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端