Javascript基础知识点整理九:Promise与async/await

IFE     2019年04月11日     分类:   前端知识体系     标签:   javascript     浏览量:   4090


简介

Promise 对象用于表示一个异步操作的最终状态(完成或失败),以及该异步操作的结果值。它可以使我们以同步的方式写异步代码。
它只有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。 只有异步操作的结果,可以决定当前是哪一种状态,而且只能从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,任何其他操作都无法改变这个状态。

用法

Promise对象也是一个构造函数,可以用来生成Promise实例,它的语法是:

const promise = new Promise(function(resolve, reject) {
  // /* executor */

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

Promise构造函数接受一个函数(executor)作为参数,它会在Promise构造函数执行时被立即调用,该函数的两个参数分别是resolvereject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

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

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

promise.catch(function(error){
    console.log(error)
});

因为 Promise.prototype.thenPromise.prototype.catch方法返回promise 对象, 所以它们可以被链式调用示意图

doSomething() // return promise
.then(result => doSomethingElse(value))
.then(newResult => doThirdThing(newResult))
.then(finalResult => console.log(`Got the final result: ${finalResult}`))
.catch(failureCallback);

注意点

为了避免意外,即使是一个已经变成 resolve 状态的 Promise,传递给 then 的函数也总是会被异步调用

Promise.resolve().then(() => console.log(2));
console.log(1); 
// 1, 2

传递到then中的函数被置入了一个微任务队列,而不是立即执行,这意味着它是在JavaScript事件队列的所有运行时结束了,事件队列被清空之后才开始执行:

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

wait().then(() => console.log(4));
Promise.resolve().then(() => console.log(2)).then(() => console.log(3));
console.log(1); 
// 1, 2, 3, 4

API

1. Promise.all()

返回一个 Promise 实例,在参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。

    const promise1 = Promise.resolve(3);
    const promise2 = 42;
    const promise3 = new Promise(function(resolve, reject) {
      setTimeout(resolve, 100, 'foo');
    });

    Promise.all([promise1, promise2, promise3]).then(function(values) {
      console.log(values);
    });
    // expected output: Array [3, 42, "foo"]

2. Promise.race()

返回一个 Promise,它将与参数中第一个传递的 promise 相同的完成方式被完成。它可以是完成( resolves),也可以是失败(rejects),这要取决于第一个完成的方式是两个中的哪个。 如果传的迭代是空的,则返回的 promise 将永远等待。

    var p1 = new Promise(function(resolve, reject) { 
        setTimeout(resolve, 500, "one"); 
    });
    var p2 = new Promise(function(resolve, reject) { 
        setTimeout(resolve, 100, "two"); 
    });

    Promise.race([p1, p2]).then(function(value) {
      console.log(value); // "two"
      // 两个都完成,但 p2 更快
    });

3. Promise.resolve()

返回一个以给定值解析后的Promise 对象。

    var original = Promise.resolve('我在第二行');
    var cast = Promise.resolve(original);
    cast.then(function(value) {
      console.log('value: ' + value);
    });
    console.log('original === cast ? ' + (original === cast));

    /*
    *  打印顺序如下,这里有一个同步异步先后执行的区别
    *  original === cast ? true
    *  value: 我在第二行
    */

4. Promise.reject(reason)

返回一个带有拒绝原因reason参数的Promise对象。

    Promise.reject("Testing static reject").then(function(reason) {
      // 未被调用
    }, function(reason) {
      console.log(reason); // "Testing static reject"
    });

    Promise.reject(new Error("fail")).then(function(result) {
      // 未被调用
    }, function(error) {
      console.log(error); // stacktrace
    });

5. Promise.prototype.finally()

返回一个Promise,在promise执行结束时,无论结果是fulfilled或者是rejected,在执行then()和catch()后,都会执行finally指定的回调函数。

由于无法知道promise的最终状态,所以finally的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。

    let isLoading = true;

    fetch(myRequest).then(function(response) {
        var contentType = response.headers.get("content-type");
        if(contentType && contentType.includes("application/json")) {
          return response.json();
        }
        throw new TypeError("Oops, we haven't got JSON!");
      })
      .then(function(json) { /* process your JSON further */ })
      .catch(function(error) { console.log(error); })
      .finally(function() { isLoading = false; });

async和await

可以用async声明一个异步函数,这个函数会返回一个promise,使用awiat可以让语法更加同步。当这个 async 函数返回一个值时,Promise 的 resolve 方法会负责传递这个值;当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值。

await 表达式,会使 async 函数暂停执行,等待 Promise 的结果出来,然后恢复async函数的执行并返回解析值(resolved)。await只能接一个promise。

注意, await 关键字仅仅在 async function中有效。如果在 async function函数体外使用 await ,你只会得到一个语法错误(SyntaxError)。

async function foo() {
  try {
    let result = await doSomething();
    let newResult = await doSomethingElse(result);
    let finalResult = await doThirdThing(newResult);
    console.log(`Got the final result: ${finalResult}`);
  } catch(error) {
    failureCallback(error);
  }
}

使用try catch 也因为它相比promise.then更像同步代码.这是发明这个语法的初衷


评论总数: 0


登陆后才可以评论