Promise: 常用 API 概述

Promise: 常用 API 概述

Tags
异步编程
ES6
JavaScript
CreatedTime
Aug 18, 2022 10:16 AM
Slug
2018-05-23-es-promise
UpdatedTime
Last updated August 18, 2022

关于Promise

  • Promise实例一旦被创建就会被执行
  • Promise过程分为两个分支:pending=>resolvedpending=>rejected
  • Promise状态改变后,依然会执行之后的代码:
const warnDemo = ctx => { const promise = new Promise(resolve => { resolve(ctx); console.log("After resolved, but Run"); // 依然会执行这个语句 }); return promise; }; warnDemo("ctx").then(ctx => console.log(`This is ${ctx}`));

then方法

Console键入以下内容:
let t = new Promise(() => {}); t.__proto__;
可以看到,then方法是定义在原型对象Promise.prototype上的。
then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。

写法

function func(args) { // 必须返回一个Promise实例 return new Promise((resolve,reject)=>{ if(...){ resolve(...) // 传入resolve函数的参数 } else { let err = new Error(...) reject(err) // reject参数必须是Error对象 } }) } func(ARGS).then(()=>{ // resolve 函数 },()=>{ // reject 函数 })

连续调用then

因为then方法返回另一个Promise对象。当这个对象状态发生改变,就会分别调用resolvereject
写法如下:
func(ARGS).then(()=>{ ... }).then( ()=>{ ... }, () => { ... } )

实例

function helloWorld(ready) { return new Promise((resolve, reject) => { if (ready) { resolve("Right"); } else { let error = new Error("arg is false"); reject(error); // 传入Error对象 } }); } helloWorld(false).then( msg => { // true:helloWorld的参数 // 参数msg:在上面的Promise对象中传入了 console.log(msg); }, error => { console.log(error.message); } );

catch方法

等同于 .then(null, rejection)。另外,then方法指定的回调函数运行中的错误,也会被catch捕获。
所以,之前的写法可以改为:
function func(args) { // 必须返回一个Promise实例 const promise = new Promise((resolve,reject)=>{ if(...){ resolve(...) } else { let err = new Error(...) reject(err) } }) return promise } func(ARGS).then(()=>{ // resolve 函数 }).catch(()=>{ // reject 函数 }).then(()=>{ // 没有错误就会跳过上面的catch })...

finally方法

指定不管 Promise 对象最后状态如何,都会执行的操作。可以理解为then方法的实例,即在resolve和reject里面的公共操作函数

all方法

用于将多个 Promise 实例,包装成一个新的 Promise 实例。它接收一个具有Iterator接口的参数。其中,item如果不是Promise对象,会自动调用Promise.resolve方法
以下代码:
const p = Promise.all([p1, p2, p3]); // p是新包装好的一个Promise对象
对于Promise.all()包装的Promise对象,只有实例的状态都变成fulfilled
可以用来操作数据库:
const databasePromise = connectDatabase(); const booksPromise = databasePromise.then(findAllBooks); const userPromise = databasePromise.then(getCurrentUser); Promise.all([booksPromise, userPromise]).then(([books, user]) => pickTopRecommentations(books, user) );
或者其中有一个变为rejected,才会调用Promise.all方法后面的回调函数。而对于每个promise对象,一旦它被自己定义catch方法捕获异常,那么状态就会更新为resolved而不是rejected
"use strict"; const p1 = new Promise((resolve, reject) => { resolve("hello"); }) .then(result => result) .catch(e => e); const p2 = new Promise((resolve, reject) => { throw new Error("p2 error"); }) .then(result => result) .catch( // 如果注释掉 catch,进入情况2 // 否则,情况1 e => e.message ); Promise.all([p1, p2]) .then( result => console.log(result) // 情况1 ) .catch( e => console.log("error in all") // 情况2 );

race方法

和all方法类似,Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。而且只要有一个状态被改变,那么新的Promise状态会立即改变
也是来自阮一峰大大的例子,如果 5 秒内无法fetech,那么p状态就会变为rejected
const p = Promise.race([ fetch("/resource-that-may-take-a-while"), new Promise(function(resolve, reject) { setTimeout(() => reject(new Error("request timeout")), 5000); }) ]); p.then(response => console.log(response)); p.catch(error => console.log(error));

重要性质

状态只改变一次

Promise 的状态一旦改变,就永久保持该状态,不会再变了。
下面代码中,Promise对象resolved后,状态就无法再变成rejected了。
"use strict"; const promise = new Promise((resolve, reject) => { resolve("ok"); // 状态变成 resolved throw new Error("test"); // Promise 的状态一旦改变,就永久保持该状态 }); promise .then(val => { console.log(val); }) .catch(error => { console.log(error.message); // 所以,无法捕获错误 });

错误冒泡

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

"吃掉错误"机制

Promise会吃掉内部的错误,并不影响外部代码的运行。所以需要catch,以防丢掉错误信息。
阮一峰大大给出的 demo:
"use strict"; const someAsyncThing = function() { return new Promise(function(resolve, reject) { // 下面一行会报错,因为x没有声明 resolve(x + 2); }); }; someAsyncThing().then(function() { console.log("everything is great"); }); setTimeout(() => { console.log(123); }, 2000);
还有如下 demo
someAsyncThing() .then(function() { return someOtherAsyncThing(); }) .catch(function(error) { console.log("oh no", error); // 下面一行会报错,因为y没有声明 y + 2; }) .catch(function(error) { console.log("carry on", error); }); // oh no [ReferenceError: x is not defined] // carry on [ReferenceError: y is not defined]