乐趣区

关于javascript:Promise一些不太常用新的方法

一、Promise 的一些办法

1.Promise.race()

(1)简介:Promise.race()办法是将多个 Promise 实例,包装成一个新的 Promise 实例

const p = Promise.race([p1, p2, p3]);

只有 p1, p2, p3 之中有一个实例的状态率先产生扭转,p 的状态就跟着扭转。

那率先扭转的 Promise 实例的返回值,就传递给 p 的回调函数。

(2)参数:和 Promise.all()的参数一样,是一个元素为 Promise 对象的数组

(3)返回值:一个新的 Promise 对象

(4)留神点:

  • Promise.race()办法如果传入的参数不是 Promise 实例,就会先调用 Promise.resolve()办法,将参数转成 Promise 实例,再进一步解决。
  • 只有参数中有其中的一个 Promise 状态产生扭转,新生成的 Promise 对象的状态也会随之产生扭转。上面的例子就是这样:
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(console.log)
.catch(console.error);

下面代码中,如果 5 秒之内 fetch 办法无奈返回后果,变量 p 的状态就会变为 rejected,从而触发 catch 办法指定的回调函数。

2.Promise.allSettled()

(1)简介:Promise.allSettled()办法承受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回后果,不论是 fulfilled 还是 rejected,包装实例才会完结。该办法由 ES2020 引入。

const promises = [fetch('/api-1'),
  fetch('/api-2'),
  fetch('/api-3'),
];

await Promise.allSettled(promises);
removeLoadingIndicator();

下面代码对服务器收回三个申请,等到三个申请都完结,不论申请胜利还是失败,加载的滚动图标就会隐没。

(2)参数:和 Promise.all()的参数一样,是一个元素为 Promise 对象的数组

(3)返回值:一个新的 Promise 对象

(4)和 Promise.all()区别:

  • Promise.allSettled()必须要等到所有传入的 Promise 状态变为 fullfilled 还是 rejected,能力返回一个 Promise 对象 。Promise.all() 返回 Promise 对象的条件有二:一是所有的 Promise 的状态都变为 fullfilled,二是其中的一个 Promise 的状态变为 rejected
  • Promise.allSettled()的返回值 allSettledPromise,状态只可能变成 fulfilled。Promise.all()则是要求传入的所有 Promise 对象的状态都变为 fullfilled 时,返回的对象的状态能力为 fullfilled,如果其中的一个 Promise 对象的状态变为 rejected,返回的对象的状态就会变为 rejected。
const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);

//allSettledPromise 的状态只可能变成 fullfilled
const allSettledPromise = Promise.allSettled([resolved, rejected]);

allSettledPromise.then(function (results) {console.log(results);
});
// [//    { status: 'fulfilled', value: 42},
//    {status: 'rejected', reason: -1}
// ]

(5)应用场景

有时候,咱们不关怀异步操作的后果,只关怀这些操作有没有完结。比方在申请某些图片的过程中显示加载中 …,这时候咱们并不去关怀图片到底有没有胜利返回,咱们只须要关怀申请这个操作是否完结。这时,Promise.allSettled()办法就很有用。如果没有这个办法,想要确保所有操作都完结,就很麻烦。Promise.all()办法就不能做到这一点。请看上面的例子:

const urls = [/* ... */];
const requests = urls.map(x => fetch(x));

try {await Promise.all(requests);
  console.log('所有申请都胜利。');
} catch {console.log('至多一个申请失败,其余申请可能还没完结。');
}

下面代码中,Promise.all()无奈确定所有申请都完结。想要达到这个目标,写起来很麻烦,有了 Promise.allSettled(),这就很容易了。

3.Promise.any()

(1)简介:Promise.any()办法承受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有参数实例有一个变成 fulfilled 状态,包装实例就会变成 fulfilled 状态;如果所有参数实例都变成 rejected 状态,包装实例就会变成 rejected 状态。

请看上面的这个例子:

var resolved = Promise.resolve(42);
var rejected = Promise.reject(-1);
var alsoRejected = Promise.reject(Infinity);

Promise.any([resolved, rejected, alsoRejected]).then(function (result) {console.log(result); // 42
});

Promise.any([rejected, alsoRejected]).catch(function (results) {console.log(results); // [-1, Infinity]
});

(2)参数:和 Promise.all()的参数一样,是一个元素为 Promise 对象的数组

(3)返回值:一个新的 Promise 对象

(4)区别:

  • 和 Promise.all()的区别 :能够说是和 Promise.all() 刚好相同,Promise.all()是所有的 Promise 的状态都变为 fullfilled 时,返回的 Promise 对象的状态才会变成 fullfilled,然而如果其中一个 Promise 状态变为 rejected,返回的 Promise 的状态就马上变为 rejected。
  • 和 Promise.race()的区别 :Promise.any() 跟 Promise.race()办法很像,只有一点不同,就是不会因为某个 Promise 变成 rejected 状态而完结 。而 Promise.race() 如果有其中的一个 Promise 对象的状态扭转,返回的 Promise 对象的状态将会随着扭转的 Promise 对象的状态的扭转而扭转。

4.Promise.try()

理论开发中,常常遇到一种状况:不晓得或者不想辨别,函数 f 是同步函数还是异步操作,然而想用 Promise 来解决它。因为这样就能够不论 f 是否蕴含异步操作,都用 then 办法指定下一步流程,用 catch 办法解决 f 抛出的谬误。个别就会采纳上面的写法。

Promise.resolve().then(f)

下面的写法有一个毛病,就是如果 f 是同步函数,那么它会在本轮事件循环的开端执行。

const f = () => console.log('now');
Promise.resolve().then(f);
console.log('next');
// next
// now

如果想要解决这个问题,能够应用 Promise.try 对 f 进行包装,这样就能够保障同步函数同步执行,异步函数异步执行。

const f = () => console.log('now');
Promise.try(f);
console.log('next');
// now
// next

另外,Promise.then()尽管能够捕捉 Promise 对象抛出的异步谬误,然而却捕捉不了同步谬误,看上面的例子:

function getUsername(userId) {return database.users.get({id: userId})
  .then(function(user) {return user.name;});
}
.catch((e) => console.log(e));

下面代码中,database.users.get()返回一个 Promise 对象,如果抛出异步谬误,能够用 catch 办法捕捉.

然而,如果 database.users.get()抛出了同步谬误(比方数据库链接谬误等),catch 就不能捕捉到这个谬误,这时就不得不应用 try…catch 去捕捉,就像这样:

try {database.users.get({id: userId})
  .then(...)
  .catch(...)
} catch (e) {// ...}

然而,如果应用 Promise.try()就能够对立应用 catch 捕捉同步或者是异步谬误

Promise.try(() => database.users.get({id: userId}))
  .then(...)
  .catch(...)

我的了解就是Promise.try 就是模仿 try 代码块,就像 promise.catch 模仿的是 catch 代码块。

5.Promise.resolve()

(1)简介:Promise.resolve()将现有的对象或其余转化为一个 Promise 对象。上面是一个应用 Promise.resolve()的例子:

const jsPromise = Promise.resolve($.ajax('/whatever.json'));        //jsPromise 是一个 Promise 对象

下面代码将 jQuery 生成的 deferred 对象转成一个新的 Promise 对象。

Promise.resolve()等价于上面的写法:

Promise.resolve('foo')
// 等价于
new Promise((resolve) => resolve('foo'));

(2)参数:

  • 参数是一个 Promise 实例

    如果参数是 Promise 实例,那么Promise.resolve 将不做任何批改、一成不变地返回这个实例。

  • 参数是一个 thenable 对象

    thenable 对象是指具备 then 办法的对象,比方上面这个对象。

// 这是一个 thenable 对象
let thenable = {then: function(resolve, reject) {resolve(42);
  }
};

// 应用 Promise.resolve()办法
let p1 = Promise.resolve(thenable);            // 会立刻执行 then 办法
p1.then(function(value) {console.log(value);  // 42
});

留神:Promise.resolve()办法会立刻执行 thenable 对象外面的 then 办法,而后将对象 p1 的状态变为 resolved,从而执行 p1.then()办法,输入 42.

  • 参数不是具备 then 办法的对象,或基本就不是对象

    如果参数是一个原始值,或者是一个不具备 then 办法的对象 ,则 Promise.resolve 办法 返回一个新的 Promise 对象,状态为 resolved。

const p = Promise.resolve('Hello');        // p 的状态肯定会变成 resolved

p.then(function (s){console.log(s)
});
// Hello

下面代码生成一个新的 Promise 对象的实例 p。因为字符串 Hello 不属于异步操作(判断办法是字符串对象不具备 then 办法),返回 Promise 实例的状态从毕生成就是 resolved,所以回调函数会立刻执行。Promise.resolve 办法的参数,会同时传给回调函数。

  • 不带有任何参数

    Promise.resolve()办法容许调用时不带参数,间接返回一个 resolved 状态的 Promise 对象。

const p = Promise.resolve();            // p 的状态肯定会变成 resolved

p.then(function () {// ...});

留神:立刻 resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的完结时执行(微工作),而不是在下一轮“事件循环”的开始时。

//setTimeout 是宏工作,在下一轮事件循环才执行
setTimeout(function () {console.log('three');
}, 0);

// 微工作,在本轮事件循环完结的时候执行
Promise.resolve().then(function () {console.log('two');
});

console.log('one');

// one
// two
// three

下面代码中,setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”完结时执行 ,console.log(‘one’) 则是立刻执行,因而最先输入。

6.Promise.reject()

(1)简介:Promise.reject(reason)办法也会返回一个新的 Promise 实例,该实例的状态为 rejected

const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))

p.then(null, function (s) {console.log(s)
});
// 出错了

下面代码生成一个 Promise 对象的实例 p,状态为 rejected,回调函数会立刻执行。

(2)留神:

留神,Promise.reject()办法的参数,会一成不变地作为 reject 的理由,变成后续办法的参数。这一点与 Promise.resolve 办法不统一。

const thenable = {then(resolve, reject) {reject('出错了');
  }
};

Promise.reject(thenable)
.catch(e => {console.log(e === thenable)
})
// true

下面代码中,Promise.reject 办法的参数是一个 thenable 对象,执行当前,前面 catch 办法的参数不是 reject 抛出的“出错了”这个字符串,而是 thenable 对象。

退出移动版