Promise
Promise 就像这个词的外表意识一样,示意一种承诺、允诺,会在前面给出一个后果,胜利 或者 失败。当初曾经成为了支流的异步编程的操作形式,写进了规范外面。
状态
Promise 有且仅有三种状态:
- 待定(pending): 初始状态,既没有被兑现,也没有被回绝。
- 已兑现(fulfilled): 意味着操作胜利实现。
- 已回绝(rejected): 意味着操作失败。
其实我感觉这个模型还是挺简略,也很好了解。就如同,你跟你女朋友求婚,她跟你说她要考虑一下,今天能力给你答案,这就是承诺(promise)。同时,这也是一个期待的过程(pending),而后你就等,等到今天你女朋友给你回答,批准(fulfilled)或者回绝(rejected),如果批准就筹备结婚了,如果不批准就等下次再求婚,哈哈哈。
那状态要怎么扭转呢?
Promise 的构造函数须要传入一个函数 executor ,这个函数须要两个入参别离是 resolve 和 rejected 两个函数,这两个办法次要是用来批改状态的。当咱们调用 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
中解决完之后,会持续走下一个 .then
的 onfulfilled
函数,不太合乎直觉。当然,如果你有马上解决异样的需要也能够这样写。
当 .then()
中短少可能返回 Promise 对象的函数时,链式调用就间接持续进行下一环操作。因而,链式调用能够在最初一个 .catch()
之前把所有的 handleRejection
都省略掉。相似地, .catch()
其实只是没有给 handleFulfilled
预留参数地位的 .then()
而已。
还是一个 Promise
这里要特地留神一个点,Promise.then()
、Promise.catch()
、Promise.finally()
这些办法会返回一个新的 Promise,这一点在其余很多文章中会疏忽这个点。 .then()
函数最初会返回一个 Promise ,如果在 .then
的 onfulfilled
(也就是入参的第一个函数)中返回一个值,或者对象,这个 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 = 0const 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()
补充:
还有一些小细节。
- Promise 一旦创立,传入的 executor 会被立即执行。
- 一个“已敲定”("settled")状态的 Promise 也能够承受操作,也就是说,前面能够接 then 或者 catch 函数。
所有 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
其余一些静态方法
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...