Promis.resolve()
如果向 Promise.resolve()传递一个非 promise 非 thenalbe 的立即值, 就会得到一个用这个值填充的 promise.
如果向 Promise.resolve()传递一个 promise, 就只会返回同一个 promise
如果向 Promise.resolve()传递了一个非 Promise 的 thenable 值, 前者会试图展开这个值, 而且展开过程中会持续到提取出一个具体的非类 Promise 的最终值.
假设我们要调用一个工具 foo(..) , 且并不确定得到的返回值是否是一个可信任的行为良好的 Promise, 但我们可以知道它至少是一个 thenable.Promise.resolve(..) 提供了可信任的 Promise 封装工具
- // 不要只是这么做:
- foo( 42 )
- .then( function(v){
- console.log( v );
- } );
- // 而要这么做:
- Promise.resolve( foo( 42 ) )
- .then( function(v){
- console.log( v );
- } );
对于用 Promise.resolve(..) 为所有函数的返回值 (不管是不是 thenable) 都封装一层. 另一个好处是, 这样做很容易把函数调用规范为定义良好的异步任务. 如果 foo(42) 有时会返回一个立即值, 有时会返回 Promise, 那么 Promise.resolve( foo(42) ) 就能够保证总会返回一个 Promise 结果
默认错误处理函数
如果一个 promise 链中的上一级 promise 抛出一个错误, 但是下一级 promise 并没有配置错误处理函数, promise 会有一个默认处理函数来处理这个错误, 即吧这个错误重新抛出给下一级 promise 的错误处理函数.
如果一直找到最后一级的 promise 都没有错误处理函数, 那么 promise 会在控制台打出一个错误信息, 并且这个错误是有可能中断 Node.JS 进程的.
DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.JS process with a non-zero exit code.
(在浏览器环境貌似并不会中断进程)
Promise 链
调用 promise 的 then 方法, 会自创建一个新的 Promise, 并且决议的值就是 then 中 resolve/reject 函数的返回值;
如果 resolve/reject 函数返回的是一个 Promise, 那么会等待这个 Promise 的决议结果, 并将决议结果作为当前 then 方法生成的 Promise 的决议值;
- var a = new Promise(function(resolve, reject) {
- resolve(10)
- }).then(
- res => {
- return b
- }
- ).then(res => {
- console.log('1err:' + res)
- return res
- }).then(res => {
- console.log('1res:' + res)
- return res
- }, err => {
- console.log('2err:' + err)
- })
- var b = new Promise(function(resolve, reject) {
- resolve(123123123123)
- })
Promise 构造器中两个回调函数
reject 很好理解就是处理错误, 那么 resolve 为什么不用 fulfill 呢? 貌似应该是处理成功请求? 实际上 resolve 的意思是决议, 也就是可能是成功的结果也可能是失败的结果; 比如所给 resolve 传入 thenable 或者一个真正的 Promise, 这个时候决议的结果取决于返回值的决议结果, 所以说 resolve 返回的有可能是成功也有可能是失败;
- var rejectedPr = new Promise( function(resolve,reject){
- // 用一个被拒绝的 promise 完成这个 promise
- resolve( Promise.reject( "Oops" ) );
- } );
- rejectedPr.then(
- function fulfilled(){
- // 永远不会到达这里
- },
- function rejected(err){
- console.log( err ); // "Oops"
- }
- );
前面提到的 reject(..) 不会像 resolve(..) 一样进行展开. 如果向 reject(..) 传入一个 Promise/thenable 值, 它会把这个值原封不动地设置为拒绝理由. 后续的拒绝处理函数接收到的是你实际传给 reject(..) 的那个 Promise/thenable, 而不是其底层的立即值.
回调函数简介
回调函数就是一个通过函数指针调用的函数. 如果你把函数的指针 (地址) 作为参数传递给另一个函数, 当这个指针被用来调用其所指向的函数时, 我们就说这是回调函数. 回调函数不是由该函数的实现方直接调用, 而是在特定的事件或条件发生时由另外的一方调用的, 用于对该事件或条件进行响应
而 then 方法的两个回调函数应该使用 onFulfilles/fulfilled 和 onRejected/rejected 因为对于 then 来说第一个回调只能处理正确的结果.
(fulfilled the promis 兑现承诺)
Promise 错误处理函数的细节
通常我们有两种写法来捕获错误:
- var a = new promise(function(resolve, reject){
- })
- // 在 then 方法的内部第二个回调捕获
- a.then(res => {
- }, err => {
- })
- // 在 catch 方法中捕获
- a.then(res => {
- }).catch(err => {
- })
那么这两种方法有什么不同? 实际上第二种方法是包含第一种方法的, 只不过 then 方法中的第二个回调被默认执行了, 而默认的错误处理回调只是简单的抛出错误, 然后就会被 catch 方法捕获; 这里就有一个问题, 如果 a 的决议是 resolve, 那么就会调用 then 的第一个成功回调, 如果这个成功回调中的具体代码中发生了错误, 第一种方法是无法捕获的, 而第二种方法是可以捕获的.
- var a = new promise(function(resolve, reject){
- resolve(12)
- })
- // 在 then 方法的内部第二个回调捕获
- a.then(res => {
- aaa() // 这里 aaa 是不存在的会发生错误
- }, err => {
- console.log(err) // 不会走这里, 所以错误不会被捕获
- })
- // 在 catch 方法中捕获
- a.then(res => {
- aaa() // 这里 aaa 是不存在的会发生错误
- }).catch(err => {
- console.log(err) // 这里会捕获 then 方法中的所有错误, 自然也能捕获 aaa 导致的错误
- })
Promise.race()的应用场景
实际上 Promise.race([p1, p1, p3])这种模式在程序设计中通常是一种被称为竞态的 bug, 但是它还是有一定的应用场景:
请求超时处理
- var p1 = new Promise(function(resolve, reject) {
- setTimeout(function() {
- resolve(2222)
- }, 2000)
- })
- // 定义一个超时函数, 如果 p1 超过这个时间还未决议, 就认为这个请求超时了.
- var timeoutPromise = new Promise(function(resolve, reject) {
- setTimeout(function() {
- reject('timeout')
- }, 1000)
- })
- Promise.race([p1, timeoutPromise]).then(res => {
- console.log(res)
- }).catch(err => {
- console.log(err)
- })
有时候我们可能会想, Promsie.race()中那些别丢弃 (比赛中失败) 的 Promise 哪里去了? 当然最后会被垃圾回收, 但是, Promsie 不能别停止, 它们依旧会完成自己的任务直到决议, 目前来看只是被默默的丢弃了, 像空气一样, 或许在以后的规范中会添加类似与 finally 之类的回调函数用于处理这些被遗弃的孩子.
来源: https://juejin.im/post/5c0791daf265da615c590bda