关于html5:一次搞懂-ES-Promise

3次阅读

共计 4581 个字符,预计需要花费 12 分钟才能阅读完成。

Promise

Promise 就像这个词的外表意识一样,示意一种承诺、允诺,会在前面给出一个后果,胜利 或者 失败。当初曾经成为了支流的异步编程的操作形式,写进了规范外面。

状态

Promise 有且仅有三种状态:

  • 待定(pending): 初始状态,既没有被兑现,也没有被回绝。
  • 已兑现(fulfilled): 意味着操作胜利实现。
  • 已回绝(rejected): 意味着操作失败。

其实我感觉这个模型还是挺简略,也很好了解。就如同,你跟你女朋友求婚,她跟你说她要考虑一下,今天能力给你答案,这就是承诺(promise)。同时,这也是一个期待的过程(pending),而后你就等,等到今天你女朋友给你回答,批准(fulfilled)或者回绝(rejected),如果批准就筹备结婚了,如果不批准就等下次再求婚,哈哈哈。

那状态要怎么扭转呢?

Promise 的构造函数须要传入一个函数 executor,这个函数须要两个入参别离是 resolverejected 两个函数,这两个办法次要是用来批改状态的。当咱们调用 resolve 函数的时候,Promise 的状态就变成 fulfilled。当咱们调用 reject 函数的时候,Promise 的状态就变成 reject。举个栗子:

new Promise((resolve, reject) => {console.log("开始求婚。")
    console.log("。。。。。")
    console.log("考虑一下。")
    setTimeout(() => {if (isHandsome || isRich) {resolve('我批准!')
        } else {reject("回绝:咱们八字不合")
        }
    }, 2000)
})

这里还要留神一点,如果一个 promise 曾经被兑现(fulfilled)或被回绝(rejected),那么咱们也能够说它处于 已敲定(settled)状态。

链式调用

这点跟 Rx 还是挺类似的,也是链式调用,这样的益处就是异步逻辑更加清晰,连贯,合乎直觉,防止了回调天堂。

咱们能够用 Promise.then()Promise.catch()Promise.finally() 这些办法将进一步的操作与一个变为已敲定状态的 Promise 关联起来。这些办法还会返回一个新生成的 Promise 对象,这个对象能够被非强制性的用来做链式调用,就像这样:

const myPromise =
  (new Promise(myExecutorFunc))
  .then(handleFulfilledA,handleRejectedA)
  .then(handleFulfilledB,handleRejectedB)
  .then(handleFulfilledC,handleRejectedC);

// 或者,这样可能会更好...

const myPromise =
  (new Promise(myExecutorFunc))
  .then(handleFulfilledA)
  .then(handleFulfilledB)
  .then(handleFulfilledC)
  .catch(handleRejectedAny);

咱们个别举荐应用第二种的写法,因为第一种写法如果在两头出错,在 .then 中解决完之后,会持续走下一个 .thenonfulfilled 函数,不太合乎直觉。当然,如果你有马上解决异样的需要也能够这样写。

.then() 中短少可能返回 Promise 对象的函数时,链式调用就间接持续进行下一环操作。因而,链式调用能够在最初一个 .catch() 之前把所有的 handleRejection 都省略掉。相似地,.catch() 其实只是没有给 handleFulfilled 预留参数地位的 .then() 而已。

还是一个 Promise

这里要特地留神一个点,Promise.then()Promise.catch()Promise.finally() 这些办法会返回一个新的 Promise,这一点在其余很多文章中会疏忽这个点。.then() 函数最初会返回一个 Promise,如果在 .thenonfulfilled(也就是入参的第一个函数)中返回一个值,或者对象,这个 Promise 的状态就会确定(settled),接着会触发下个 .then() 中的 onfulfilled,并将这个 值 或者 对象作为入参传入。

诶,等一下,如果在 .then() 中间接返回一个 Promise 呢?

这个时候就会间接替换返回的 Promise。就跟 RxJava 中的 flatMap 操作挺类似的。MDN 中有阐明:

链式调用中的 promise 们就像俄罗斯套娃一样,是嵌套起来的,但又像是一个栈,每个都必须从顶端被弹出。链式调用中的第一个 promise 是嵌套最深的一个,也将是第一个被弹出的。

(promise D, (promise C, (promise B, (promise A) ) ) )

当存在一个 nextValue 是 promise 时,就会呈现一种动静的替换成果。return 会导致一个 promise 被弹出,但这个 nextValue promise 则会被推入被弹出 promise 原来的地位。对于下面所示的嵌套场景,假如与 “promise B” 相干的 .then() 返回了一个值为 “promise X” 的 nextValue。那么嵌套的后果看起来就会是这样:

(promise D, (promise C, (promise X) ) )

观察者模式?

而且一个 Promise 可能会参加不止一次的嵌套,感觉也像是观察者的模式,并反对多个观察者。对于上面的代码,promiseA 向 ” 已敲定 ”(”settled”)状态的过渡会导致两个实例的 .then 都被调用。

const promiseA = new Promise(myExecutorFunc);
const promiseB = promiseA.then(handleFulfilled1, handleRejected1);
const promiseC = promiseA.then(handleFulfilled2, handleRejected2); 

写点代码

讲了这么多,写点代码吧,就写一个,女朋友屡次回绝之后看到了你的诚意,最初批准的故事。手动狗头。

let count = 0

const propose = () => {return new Promise((resolve, reject) => {console.log("开始求婚。")
        console.log("。。。。。")
        console.log("考虑一下。")
        setTimeout(() => {if (count < 3) {reject("回绝:咱们八字不合")
                count++
            } else {resolve('我批准!')
            }
        }, 2000)
    })
}

const startPropose = () => {propose()
        .then((result) => {console.log(result)
            console.log("完结撒花")
            console.log("、·、·、、·、·、·、")
        },)
        .catch((e) => {
            {console.error(e)
                console.log("被回绝了,下次再求婚。")
                setTimeout(() => {startPropose()
                }, 3000)
            }
        })
}

startPropose()

补充:

还有一些小细节。

  1. Promise 一旦创立,传入的 executor 会被立即执行。
  2. 一个“已敲定”(”settled”)状态的 Promise 也能够承受操作,也就是说,前面能够接 then 或者 catch 函数。
  3. 所有 Promise 都是异步的,即使是“已敲定”(“settled”)了的 Promise 也是如此。一个曾经处于 ” 已敲定 ”(”settled”)状态的 promise 中的操作只有 promise 链式调用的栈被清空了和一个事件循环过来了之后才会被执行。这种成果跟 setTimeout(action, 10) 特地类似。

    const promiseA = new Promise((resolutionFunc,rejectionFunc) => {resolutionFunc(777);
    });
    // 这时,"promiseA" 曾经被敲定了。promiseA.then((val) => console.log("asynchronous logging has val:",val) );
    console.log("immediate logging");
    
    // produces output in this order:
    // immediate logging
    // asynchronous logging has val: 777
  4. 其余一些静态方法

    • Promise.all(iterable)

      这个办法返回一个新的 promise 对象,该 promise 对象在 iterable 参数对象里所有的 promise 对象都胜利的时候才会触发胜利,一旦有任何一个 iterable 外面的 promise 对象失败则立刻触发该 promise 对象的失败。这个新的 promise 对象在触发胜利状态当前,会把一个蕴含 iterable 里所有 promise 返回值的数组作为胜利回调的返回值,程序跟 iterable 的程序保持一致;如果这个新的 promise 对象触发了失败状态,它会把 iterable 里第一个触发失败的 promise 对象的错误信息作为它的失败错误信息。Promise.all 办法常被用于解决多个 promise 对象的状态汇合。(能够参考 jQuery.when 办法 — 译者注)

    • Promise.allSettled(iterable)

      等到所有 promises 都已敲定(settled)(每个 promise 都已兑现(fulfilled)或已回绝(rejected))。返回一个 promise,该 promise 在所有 promise 实现后实现。并带有一个对象数组,每个对象对应每个 promise 的后果。

    • Promise.any(iterable)

      接管一个 Promise 对象的汇合,当其中的一个 promise 胜利,就返回那个胜利的 promise 的值。

    • Promise.race(iterable)

      当 iterable 参数里的任意一个子 promise 被胜利或失败后,父 promise 马上也会用子 promise 的胜利返回值或失败详情作为参数调用父 promise 绑定的相应句柄,并返回该 promise 对象。

    • Promise.reject(reason)

      返回一个状态为失败的 Promise 对象,并将给定的失败信息传递给对应的解决办法

    • Promise.resolve(value)

      返回一个状态由给定 value 决定的 Promise 对象。如果该值是 thenable(即,带有 then 办法的对象),返回的 Promise 对象的最终状态由 then 办法执行决定;否则的话(该 value 为空,根本类型或者不带 then 办法的对象), 返回的 Promise 对象状态为 fulfilled,并且将该 value 传递给对应的 then 办法。通常而言,如果您不晓得一个值是否是 Promise 对象,应用 Promise.resolve(value) 来返回一个 Promise 对象, 这样就能将该 value 以 Promise 对象模式应用。

参考:MDN(https://developer.mozilla.org…

正文完
 0