JavaScript笔记(Promise 对象、async 和 await)

之前搞了一个拖了很长时间都没搞好的项目,bug 也多,后来迫于无奈就完全推倒重写了。这次重写完全就是怎么开心怎么来,以前那些看过但没去接触、用过的 classcanvas 画布、[...list] 语法糖等等,这次全拿来当主力了,然后着重面向对象编程的概念,最后突然发现这个觉得很难搞的项目原来弄起来挺轻松。
由此而来想法就是学习的东西不能只看了不用呀,不能固步自封。

1 Promise 对象

参考文章《Promise 对象》

Promise 简单说就是一个 容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种 异步 操作都可以用同样的方法进行处理。

Promise 有以下特点:

  • 对象状态不受外界的影响,Promise 对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。只有 异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
  • 一旦状态改变,就不会再变,任何时候都可以得到这个结果。

下面代码创造一个 promise对象:

const promise = new Promise((relsove, reject) => {
	// ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolvereject
resolve 函数的作用是,将 Promise 对象的状态从 pending 变为 resolved,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去
reject 函数的作用是,将 Promise 对象的状态从 pending 变为 rejected,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去(即主动调用 reject 函数或捕获异常导致状态从 pending 变为 rejected)。

1.1 then 方法

Promise 实例生成以后,可以用 then 方法分别指定 resolved 状态和 rejected 状态的回调函数,then 方法接受两个回调函数作为参数,第一个回调函数是 Promise 对象的状态变为 resolved 时调用,第二个回调函数是 Promise 对象的状态变为 rejected 时调用,同时 then 方法返回一个新的 Promise 对象,所以可以采用链式的方法调用 Promise 对象如:

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

下面是一个简单的例子:

function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done');
  });
}

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

重点需要注意的是 Promise 对象一旦创建就会立刻执行,如:

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');

上面依次输出的内容是:

Promise
Hi!
resolved.

1.2 catch 方法

catch 方法其实就是 then(null, rejection) 的别名,另一种写法,如:

p.then((val) => console.log('fulfilled:', val))
  .catch((err) => console.log('rejected', err));

// 等同于
p.then((val) => console.log('fulfilled:', val))
  .then(null, (err) => console.log("rejected:", err));

一般来说,不要在 then 方法里面定义 Reject 状态的回调函数(即 then 的第二个参数),总是使用 catch 方法。

如果 Promiseresolve 语句后面,此时抛出错误是无效的。因为 Promise 的状态一旦改变,就永久保持该状态,不会再变了,如:

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

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

1.3 finally 方法

finally 方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。finally 方法的回调函数不接受任何参数

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

2 asyncawait

参考文章 《async 函数》

async 用于修饰函数,它表示函数里有异步操作,而 await 表示紧跟在后面的表达式需要等待结果
正常情况下,await 命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。
下面代码表示一个计时器:

function sleep(interval) {
  return new Promise(resolve => {
    setTimeout(resolve, interval);
  })
}

// 用法
async function one2FiveInAsync() {
  for(let i = 1; i <= 5; i++) {
    console.log(i);
    await sleep(1000).then(() => console.log("1 秒过去"));
  }
}

one2FiveInAsync();

async 函数返回的 Promise 对象,但它的返回必须等到内部所有 await 命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到 return 语句或者抛出错误。也就是说,只有 async 函数内部的异步操作执行完,才会执行 then 方法指定的回调函数。
而任何一个 await 语句后面的 Promise 对象变为 reject 状态,那么整个 async 函数都会中断执行。如:

async function f() {
  await Promise.reject('出错了');
  await Promise.resolve('hello world'); // 不会执行
}

有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。此时可以提前捕获错误,如:

async function f() {
  await Promise.reject('出错了').catch(e => console.log(e));
  return await Promise.resolve('hello world');
}

f().then(v => console.log(v));
// 出错了
// hello world

也可以使用 try...catch 的形式,如:

async function f() {
  try {
    await new Promise(function (resolve, reject) {
      throw new Error('出错了');
    });
  } catch(e) {
  }
  return await('hello world');
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值