当前位置: 首页 > news >正文

麦包包在网站建设方面网站设计报价是多少

麦包包在网站建设方面,网站设计报价是多少,网络技术论坛,桥头仿做网站前言 这可能是手写promise较清晰的文章之一。 由浅至深逐步分析了原生测试用例#xff0c;以及相关Promise/A规范。阅读上推荐以疑问章节为切入重点#xff0c;对比Promise/A规范与ECMAScript规范的内在区别与联系#xff0c;确定怎样构建异步任务和创建promise实例。然后开… 前言 这可能是手写promise较清晰的文章之一。 由浅至深逐步分析了原生测试用例以及相关Promise/A规范。阅读上推荐以疑问章节为切入重点对比Promise/A规范与ECMAScript规范的内在区别与联系确定怎样构建异步任务和创建promise实例。然后开始手写章节过程中代码与测试可参考 promise-coding 仓库。 也试着回答以下关键问题。 什么是广义对象如何检验promise类型promise与thenable两类型有何区别 疑问 如果不太清楚Promise建议参考《ECMAScript 6 入门》预习下Promise相关用法知识。 除此之外对规范也要有大致认识我们将根据几个疑问来细致阐述。 什么是 Promise/A 规范 Promise有多种社区规范例如 Promise/A、Promise/B、Promise/D 和 Promises/KISS 等。 Promise/A 在Promise/A之上规范了术语并拓展了参数行为省略了一些有问题的部分。 Promise/A有很多实现例如第三方库 q、when 和 bluebird 等。实际上任何Promise通过测试都被认为是对Promise/A规范的一种实现。 Promise/A规范官方测试用例为 promises-aplus-tests 原生 Promise 实现了 Promise/A 在Promise/A规范 The ECMAScript Specification 章节中。 The ECMAScript Specification ... Largely due to the actions of the Promises/A community, the Promise global specified by ECMAScript and present in any conforming JavaScript engine is indeed a Promises/A implementation! 叙述了JavaScript引擎中的Promise也是对Promise/A规范的一种实现。 为什么呢 Promise/A规范内容上仅说明了Promise状态和then方法。 ECMAScript规范不仅规定Promise为构造函数还添加了静态方法例如Promise.resolve、Promise.all和Promise.race等新增了原型方法Promise.prototype.catch和Promise.prototype.finally等。其中Promise.prototype.then相关内容则是根据Promise/A规范转化而来。 我们知道JavaScript就是对ECMAScript规范的一种实现而ECMAScript规范中Promise.prototype.then相关内容又继承了Promise/A规范。 那么可以说JavaScript引擎中的Promise即原生Promise就是对Promise/A规范的一种实现。 如何构建异步任务 Promise/A规范规定then方法接收两个参数。 promise.then(onFulfilled, onRejected)在 2.2.4 小结中明确了参数必须以异步形式运行。 2.2.4. onFulfilled or onRejected must not be called until the execution context stack contains only platform code. 注解 3.1 补充可用宏任务setTimeout和setImmediate或者微任务MutationObserver浏览器环境和process.nextTicknode环境达到异步。 3.1. ...In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a macro-task mechanism such as setTimeout or setImmediate, or with a micro-task mechanism such as MutationObserver or process.nextTick. 综上所述Promise/A规范仅规定了参数以异步形式运行并未规定是宏任务还是微任务。 注意V8引擎内部为微任务考虑一致性推荐 queueMicrotask 创建微任务兼容性相对较好 如何创建 promise Promise/A规范并未提及如何创建promise。 ECMAScript6规范发布以来多数是以构造函数方式创建promise。 new Promise(executor)实际上在此之前还流行一种Deferred方式例如 JQuery.Deferred。 $.Deferred()我们以定时器为例对比下两者差异。 // ECMAScript6 Promise const promise new Promise(resolve {setTimeout(() {resolve(1)}, 1000) })promise.then(v {console.log(v) // 1 })// JQuery Deferred const deferred $.Deferred()deferred.promise().then(v {console.log(v) // 1 })setTimeout(() {deferred.resolve(1) }, 1000)你也注意到了吧Deferred方式相对更加灵活可以在任何时机修改状态。而Promise方式自由度减少了很多不仅代码层级多了一层而且只能在函数参数中修改状态。 可能你会问那为什么TC39放弃了Deferred而决定了Promise构造器方式呢 Deferred方式存在一个较严重的缺陷即在业务流程阶段不容易捕获异常。 const deferred $.Deferred()deferred.promise().catch(v {console.log(v) });(function () {throw new Error() // Uncaught Errordeferred.resolve(1) })()如果想让promise捕获异常业务代码可修改为。 ;(function () {try {throw new Error()} catch (error) {deferred.reject(error)}deferred.resolve(1) })()而Promise构造器方式则非常容易。 const promise new Promise(resolve {throw new Error()resolve(1) })promise.catch(v {console.log(v) // Error })两相比较下ECMAScript6确定了以构造器方式创建promise。 个人认为Deferred更多是一个发布订阅器而Promise则相对更加强大是一个异步流程解决方案ECMAScript6规范将其独立为一个模块是相当合理的 手写 Promise/A更多地是规范了算法逻辑并未规定语法层面的实现方式。 我们可以参考原生Promise语法并结合简单用例手写以符合Promise/A规范。 注意Promise/A规范相关内容将特别标注 实例初始属性 原生创建Promise实例。 new Promise(() {}) // { // [[PromiseState]]: pending, // [[PromiseResult]]: undefined, // }相关特征包括。 Promise为构造函数默认状态为pending默认结果为undefined三种状态分别为等待态pending、解决态fulfilled和拒绝态rejected——「Promise/A 2.1」 代码编写如下其中属性[[PromiseState]]用于保存状态[[PromiseResult]]用于保存结果。 const PromiseState [[PromiseState]] const PromiseResult [[PromiseResult]]const PENDING pending const FULFILLED fulfilled const REJECTED rejectedclass Promise {[PromiseState] PENDING;[PromiseResult] undefined }ES2020规范 proposal-class-fields 允许实例属性定义在类内部的最顶层相对更加清晰简洁 executor 执行器 原生Promise传参函数。 new Promise(function executor() {console.log(1) // 1 }) console.log(2) // 2new Promise((resolve, reject) {resolve(3) }) // { // [[PromiseState]]: fulfilled, // [[PromiseResult]]: 3, // }new Promise((resolve, reject) {reject(4) }) // { // [[PromiseState]]: rejected, // [[PromiseResult]]: 4, // }相关特征包括。 实例创建过程中参数executor将同步执行执行器executor包括resolve和reject两个函数参数resolve执行实例状态修改为解决态reject执行实例状态修改为拒绝态 以下为优化代码注意私有方法用箭头函数可将内部this指向实例对象。 class Promise {...#resolve value {this[PromiseState] FULFILLEDthis[PromiseResult] value}#reject reason {this[PromiseState] REJECTEDthis[PromiseResult] reason}constructor(executor) {executor(this.#resolve, this.#reject)} }ES2020规范 proposal-class-fields 允许实例定义私有属性或方法仅可在类内部使用外部无法使用 状态不可变性 原生Promise修改状态。 new Promise((resolve, reject) {resolve(1)resolve(2) }) // { // [[PromiseState]]: fulfilled, // [[PromiseResult]]: 1, // }new Promise((resolve, reject) {resolve(3)reject(4) }) // { // [[PromiseState]]: fulfilled, // [[PromiseResult]]: 3, // }相关特征包括。 处于解决态或者拒绝态一定不能再修改为任何状态——「Promise/A 2.1.2 / 2.1.3」处于等待态的时候可能变为解决态或者拒绝态——「Promise/A 2.1.1」 代码优化为。 #resolve value {if (this[PromiseState] PENDING) {this[PromiseState] FULFILLEDthis[PromiseResult] value} } #reject reason {if (this[PromiseState] PENDING) {this[PromiseState] REJECTEDthis[PromiseResult] reason} }方法传参 原生Promise上then方法传参。 const p new Promise((resolve, reject) {resolve() })p.then(undefined, undefined)相关特征包括。 promise必须有then方法且接收两个参数onFulfilled和onRejected——「Promise/A 2.2」onFulfilled和onRejected都是可选参数若不是函数必须被忽略——「Promise/A 2.2.1」onFulfilled和onRejected一定被作为普通函数调用——「Promise/A 2.2.5」 代码修改为。 class Promise {...then(onFulfilled, onRejected) {onFulfilled typeof onFulfilled function ? onFulfilled : () {}onRejected typeof onRejected function ? onRejected : () {}} }参数为非函数时为保证可被调用暂时返回普通函数 then 方法 原生Promise执行then方法。 const p1 new Promise((resolve, reject) {resolve(1) }) p1.then(v {console.log(v) // 1 })const p2 new Promise((resolve, reject) {reject(2) }) p2.then(undefined, v {console.log(v) // 2 })相关特征包括。 如果onFulfilled或onRejected是一个函数必须在promise被解决或被拒绝后调用且promise值或原因作为第一个参数——「Promise/A 2.2.2 / 2.2.3」 代码修改为。 then(onFulfilled, onRejected) {...if (this[PromiseState] FULFILLED) {onFulfilled(this[PromiseResult])}if (this[PromiseState] REJECTED) {onRejected(this[PromiseResult])} }异步 executor 目前代码并未完全符合「Promise/A 2.2.2 / 2.2.3」规范例如executor为异步情况时还会存在一些问题。 const p new Promise((resolve, reject) {setTimeout(() {resolve(1)}, 1000) })p.then(v {console.log(v) })控制台没有打印任何内容 为什么呢 实例p在创建完成后还处在等待态。紧接着执行then方法then方法内部没有等待态相关逻辑也就没有任何操作。1s后resolve执行也仅仅是将p状态修改为解决态。 如何解决呢 可以在等待态就保存onFulfilled和onRejected函数在resolve修改状态时再执行。 代码优化为。 class Promise {...#onFulfilledCallBack undefined#onRejectedCallBack undefined#resolve value {if (this[PromiseState] PENDING) {...this.#onFulfilledCallBack?.(this[PromiseResult])}}#reject reason {if (this[PromiseState] PENDING) {...this.#onRejectedCallBack?.(this[PromiseResult])}}...then(onFulfilled, onRejected) {...if (this[PromiseState] PENDING) {this.#onFulfilledCallBack onFulfilledthis.#onRejectedCallBack onRejected}} }?.为ES2020规范中 proposal-optional-chaining 可选链操作符 多次调用 then 原生Promise多次调用then方法。 const p new Promise((resolve, reject) {setTimeout(() {resolve()}, 1000) })p.then(() {console.log(1) // 1 })p.then(() {console.log(2) // 2 })p.then(() {console.log(3) // 3 })相关特征包括。 then方法函数参数按语法顺序执行同一promise上then方法可能被多次调用——「Promise/A 2.2.6」 代码优化如下注意为了保证顺序两数组内函数都是先进先出。 class Promise {...#onFulfilledCallBacks []#onRejectedCallBacks []#resolve value {if (this[PromiseState] PENDING) {...while (this.#onFulfilledCallBacks.length) {this.#onFulfilledCallBacks.shift()(this[PromiseResult])}}}#reject reason {if (this[PromiseState] PENDING) {...while (this.#onRejectedCallBacks.length) {this.#onRejectedCallBacks.shift()(this[PromiseResult])}}}...then(onFulfilled, onRejected) {...if (this[PromiseState] PENDING) {this.#onFulfilledCallBacks.push(onFulfilled)this.#onRejectedCallBacks.push(onRejected)}} }返回 promise 原生Promise返回值。 const p new Promise(() {})p.then() // { // [[PromiseState]]: pending, // [[PromiseResult]]: undefined, // }相关特征包括。 then方法必须返回一个新promise——「Promise/A 2.2.7」 代码暂时修改为。 then(onFulfilled, onRejected) {...if (this[PromiseState] PENDING) {...}const promise new Promise(() {})return promise }函数参数返回值 原生Promise函数参数onFulfilled返回数值。 const p new Promise((resolve, reject) {resolve() })p.then(() {return 1 }) // { // [[PromiseState]]: fulfilled, // [[PromiseResult]]: 1, // }相关特征包括。 如果onFulfilled或onRejected返回一个值x运行promise解决程序——「Promise/A 2.2.7.1」如果x不是一个对象或函数用x解决promise——「Promise/A 2.3.4」 何为promise解决程序呢 「Promise/A 2.3」叙述是一个抽象操作可表示为[[Resolve]](promise, x)。其中主要根据x类型决定新promise的状态和结果。 比如x不是一个对象或函数例如数值则新promise状态将确定为解决态结果为x即用x解决promise。 // { // [[PromiseState]]: fulfilled, // [[PromiseResult]]: x, // }那么如何在onFulfilled或onRejected返回数值x时又修改新promise状态和结果呢 then(onFulfilled, onRejected) {...if (this[PromiseState] FULFILLED) {const x onFulfilled(this[PromiseResult])}...const promise new Promise(() {})return promise }你可能想到了。 then(onFulfilled, onRejected) {...const promise new Promise(() {})if (this[PromiseState] FULFILLED) {const x onFulfilled(this[PromiseResult])promise.#resolve(x)}...return promise }可修改状态也符合规范但个人认为此方式存在一些缺陷。 将实例属性resolve私有化就是为了限制外部访问。以promise.#resolve访问而非this.#resolve已经处于外部访问的范畴了思路上不是很合理。 还有更好的办法吗 我们知道在executor执行器上resolve和reject两个参数也可修改状态。 如果将if语句体迁移至executor内部有没有可能呢答案是可以的。 then(onFulfilled, onRejected) {...const promise new Promise((resolve, reject) {if (this[PromiseState] FULFILLED) {const x onFulfilled(this[PromiseResult])resolve(x)}...})return promise }if语句体在executor外部时同步执行。在executor内部时也是同步执行 相关特征完全实现了吗并没有。 若executor为异步情况时还存在一些问题。 const p1 new Promise((resolve, reject) {setTimeout(() {resolve()}, 1000) })const p2 p1.then(() {return 2 })setTimeout(() {console.log(p2)// {// [[PromiseState]]: pending,// [[PromiseResult]]: undefined,// } }, 2000)控制台打印内容与原生不一致 为什么呢 实例p1处于等待态执行then方法将onFulfilled保存至数组中。1s后resolve执行p1状态修改为解决态紧接着取出运行onFulfilledp2状态无任何变化。 我们可以在onFulfilled执行时对返回值x稍加处理。 const promise new Promise((resolve, reject) {...if (this[PromiseState] PENDING) {this.#onFulfilledCallBacks.push(() {const x onFulfilled(this[PromiseResult])resolve(x)})...} })处理函数 为了统一处理不同类型x值并严格实现规范「Promise/A 2.3」中各子章节。 修改代码并创建resolvePromise函数参数暂时为x和resolve。 class Promise {...then(onFulfilled, onRejected) {...const promise new Promise((resolve, reject) {if (this[PromiseState] FULFILLED) {const x onFulfilled(this[PromiseResult])resolvePromise(x, resolve)}...if (this[PromiseState] PENDING) {this.#onFulfilledCallBacks.push(() {const x onFulfilled(this[PromiseResult])resolvePromise(x, resolve)})...}})return promise} }function resolvePromise(x, resolve) {resolve(x) }研读部分子章节。 2.3.1. If promise and x refer to the same object, reject promise with a TypeError as the reason. 2.3.2.2. If/when x is fulfilled, fulfill promise with the same value. 2.3.2.3. If/when x is rejected, reject promise with the same reason. 可确认参数promise和x、resolve、reject。 const promise new Promise((resolve, reject) {if (this[PromiseState] FULFILLED) {const x onFulfilled(this[PromiseResult])resolvePromise(promise, x, resolve, reject)}...if (this[PromiseState] PENDING) {this.#onFulfilledCallBacks.push(() {const x onFulfilled(this[PromiseResult])resolvePromise(promise, x, resolve, reject)})...} })function resolvePromise(promise, x, resolve, reject) {resolve(x) }抛出异常 原生Promise抛出异常。 const p new Promise((resolve, reject) {resolve() })p.then(() {throw new Error() }).then(undefined, v {console.log(v) // Error })相关特征包括。 如果onFulfilled或onRejected抛出一个异常e新promise为拒绝态且原因为e——「Promise/A 2.2.7.2」 代码优化为。 const promise new Promise((resolve, reject) {if (this[PromiseState] FULFILLED) {try {const x onFulfilled(this[PromiseResult])resolvePromise(promise, x, resolve, reject)} catch (e) {reject(e)}}... })类似地executor为异步情况时也存在一些问题。 const p new Promise((resolve, reject) {setTimeout(() {resolve()}, 1000) })p.then(() {throw new Error() // Uncaught Error }).then(undefined, v {console.log(v) })未捕获到异常 为什么呢 实例p处于等待态执行then方法将onFulfilled保存。1s后resolve执行p状态修改为解决态紧接着取出onFulfilled运行内部抛出了异常。 代码优化为。 const promise new Promise((resolve, reject) {...if (this[PromiseState] PENDING) {this.#onFulfilledCallBacks.push(() {try {const x onFulfilled(this[PromiseResult])resolvePromise(promise, x, resolve, reject)} catch (e) {reject(e)}})...} })异步任务 原生Promise异步。 const p new Promise((resolve, reject) {resolve(1) })console.log(2) // 2 p.then(v {console.log(v) // 1 }) console.log(3) // 3注意打印顺序2 3 1 相关特征包括。 onFulfilled或onRejected必须以异步形式运行——「Promise/A 2.2.4」 代码简单修改为。 const queueTask queueMicrotaskclass Promise {...then() {const promise new Promise((resolve, reject) {if (this[PromiseState] FULFILLED) {try {queueTask(() {const x onFulfilled(this[PromiseResult])resolvePromise(promise, x, resolve, reject)})} catch (e) {reject(e)}}...})return promise} }注意try...catch并不能捕获到异步函数内抛出的异常例如。 try {setTimeout(() {throw new Error() // Uncaught Error}) } catch (error) {console.log(error) }那如何优化呢 我们可以将全部try...catch语句放到异步函数中。 const promise new Promise((resolve, reject) {if (this[PromiseState] FULFILLED) {queueTask(() {try {const x onFulfilled(this[PromiseResult])resolvePromise(promise, x, resolve, reject)} catch (e) {reject(e)}})}... })类似地executor为异步情况时也存在一些问题。 const p new Promise(resolve {setTimeout(() {console.log(1) // 1resolve(2)console.log(3) // 3}, 1000) })p.then(v {console.log(v) // 2 })打印顺序1 2 3原生打印顺序1 3 2 为什么呢 onFulfilled没有以异步形式运行。 代码修改为。 const promise new Promise((resolve, reject) {...if (this[PromiseState] PENDING) {this.#onFulfilledCallBacks.push(() {queueTask(() {try {const x onFulfilled(this[PromiseResult])resolvePromise(promise, x, resolve, reject)} catch (e) {reject(e)}})})...} })合并重复代码。 const promise new Promise((resolve, reject) {const resolved () {queueTask(() {try {const x onFulfilled(this[PromiseResult])resolvePromise(promise, x, resolve, reject)} catch (e) {reject(e)}})}const rejected () {queueTask(() {try {const x onRejected(this[PromiseResult])resolvePromise(promise, x, resolve, reject)} catch (e) {reject(e)}})}if (this[PromiseState] FULFILLED) {resolved()}if (this[PromiseState] REJECTED) {rejected()}if (this[PromiseState] PENDING) {this.#onFulfilledCallBacks.push(resolved)this.#onRejectedCallBacks.push(rejected)} })参数优化 原生Promise值穿透。 const p1 new Promise((resolve, reject) {resolve(1) }) p1.then(undefined) // { // [[PromiseState]]: fulfilled, // [[PromiseResult]]: 1, // }const p2 new Promise((resolve, reject) {reject(2) }) p2.then(undefined, undefined) // { // [[PromiseState]]: rejected, // [[PromiseResult]]: 2, // }相关特征包括。 如果onFulfilled不是一个函数且原promise被解决新promise必须也被解决且值与原promise相同——「Promise/A 2.2.7.3」如果onRejected不是一个函数且原promise被拒绝新promise必须也被拒绝且原因与原promise相同——「Promise/A 2.2.7.4」 代码优化如下。 then(onFulfilled, onRejected) {onFulfilled typeof onFulfilled function ? onFulfilled : value valueonRejected typeof onRejected function ? onRejected : reason { throw reason }... }注意throw抛出异常将被try...catch捕获进而拒绝新promise 类型 如何处理不同类型x呢 还是参考规范「Promise/A 2.3」各子章节以优化resolvePromise处理函数。 循环引用 原生Promise循环引用。 const p1 new Promise((resolve, reject) {resolve() })const p2 p1.then(() {return p2 }) // { // [[PromiseState]]: rejected, // [[PromiseResult]]: TypeError: Chaining cycle detected for promise #Promise, // }相关特征包括。 如果promise和x引用同一对象则拒绝promise原因为一个TypeError——「Promise/A 2.3.1」 代码优化为。 function resolvePromise(promise, x, resolve, reject) {if (promise x) {return reject(new TypeError(Chaining cycle detected for promise #Promise))}resolve(x) }传递性 原生Promise函数参数onFulfilled返回promise。 const p1 new Promise((resolve, reject) {resolve() }) const p2 new Promise((resolve, reject) {reject(1) })p1.then(() {return p2 }) // { // [[PromiseState]]: rejected, // [[PromiseResult]]: 1, // }相关特征包括。 如果x是等待态promise必须保持等待态直到x被解决或被拒绝——「Promise/A 2.3.2.1」如果x是解决态用相同的值解决promise——「Promise/A 2.3.2.2」如果x是拒绝态用相同的原因拒绝promise——「Promise/A 2.3.2.3」 也就是promise状态与x始终都保持一致。 可能会存在x初始为等待态然后又转变为解决态或拒绝态。过程中两者状态始终一致若x状态转变promise状态也将转变。 那如何知道x状态转变呢答案就是then方法。 x.then(onFulfilled, onRejected)x转变为解决态时将运行onFulfilled转变为拒绝态时将运行onRejected。 那我们就可在onFulfilled或onRejected内部去修改promise状态。 代码优化为。 function resolvePromise(promise, x, resolve, reject) {...if (x instanceof Promise) {x.then(value {resolve(value)}, reason {reject(reason)})} else {resolve(x)} }简化为。 function resolvePromise(promise, x, resolve, reject) {...if (x instanceof Promise) {x.then(resolve, reject)} else {resolve(x)} }广义对象 何为广义对象呢 能添加属性或方法的变量都称之为广义上的对象例如数组、函数等。 创建isObject工具函数更多参考 lodash.isObject。 function isObject(value) {const type typeof valuereturn value ! null (type object || type function) }然后阅读规范「Promise/A 2.3.3」小节省略部分暂时不考虑。 如果x是一个对象或函数广义对象 让then为x.then如果获取x.then导致抛出了一个异常e用e作为原因拒绝promise如果then是一个函数用x作为this调用它且包含两个参数分别为resolvePromise和rejectPromise 如果resolvePromise用一个值y调用运行[[Resolve]](promise, y)如果rejectPromise用一个原因r调用用r拒绝promise...如果调用then抛出了一个异常e ...否则用e作为作为原因拒绝promise 如果then不是一个函数用x解决promise 转译为代码。 function resolvePromise(promise, x, resolve, reject) {...if (x instanceof Promise) {...} else {if (isObject(x)) {var thentry {then x.then} catch (e) {reject(e)}if (typeof then function) {try {then.call(x,y {resolvePromise(promise, y, resolve, reject)},r {reject(r)})} catch (e) {reject(e)}} else {resolve(x)}} else {resolve(x)}} }规范中运行[[Resolve]](promise, y)即递归resolvePromise为什么呢 原因在于y值可能还是promise或者广义对象等等。 我们来看一个原生Promise示例。 const p new Promise(resolve {resolve() }) const thenable1 {then(reslove) {reslove(1)}, } const thenable2 {then(resolve) {resolve(thenable1)}, }p.then(() {return thenable2 }) // { // [[PromiseState]]: fulfilled, // [[PromiseResult]]: 1, // }优先级 以下为刚才省略的部分。 如果then是一个函数... ......如果resolvePromise和rejectPromise都被调用或者对其中一个多次调用那么第一次调用优先以后的调用都会被忽略如果调用then抛出了... 如果resolvePromise或rejectPromise已经被调用则忽略它... 为了限制哪种情况呢 还是来看一个原生Promise示例。 const p new Promise(resolve {resolve() }) const thenable1 {then(reslove) {setTimeout(() {reslove(2)}, 0)}, } const thenable2 {then(resolve) {resolve(thenable1)resolve(1)}, }p.then(() {return thenable2 }) // { // [[PromiseState]]: fulfilled, // [[PromiseResult]]: 2, // }代码如何优化呢 我们可定义布尔变量called标记是否运行参数resolvePromise或rejectPromise。然后在第一次运行时将called修改为true而以后的都会return被忽略。 if (typeof then function) {var called falsetry {then.call(x,y {if (called) returncalled trueresolvePromise(promise, y, resolve, reject)},r {if (called) returncalled truereject(r)})} catch (e) {if (called) returncalled truereject(e)} }thenable 规范「Promise/A 1.1」小结陈述了。 promise是一个对象或函数广义对象存在then方法且行为符合规范。 第三方Promise库、原生Promise以及我们手写版本Promise创建的promise实例其实都是标准的promise类型。 而代码中x instanceof Promise语句检验是否为promise类型就有问题了。例如x被第三方库创建也是标准promise类型但是并不会运行if语句体而是错误地运行else语句体。 function resolvePromise(promise, x, resolve, reject) {...if (x instanceof Promise) {...} else {...} }还有方法可确定x为promise类型吗答案是没有。 怎么办呢 既然无法检验promise类型那就退而求其次检验类似promise类型的即鸭式辩型。 鸭子类型duck typing也叫鸭式辩型一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子那么这只鸟就可以被称为鸭子 规范「Promise/A 1.2」提出了thenable类型即定义了then方法的对象或函数。 {then() {...}, }thenable是promise的鸭子类型 检验是否为promise类型则降级为检验是否为thenable类型。 代码修改为。 function resolvePromise(promise, x, resolve, reject) {if (promise x) {return reject(new TypeError(Chaining cycle detected for promise #Promise))}if (isObject(x)) {var thentry {then x.then} catch (e) {reject(e)}if (typeof then function) {var called falsetry {then.call(x,y {if (called) returncalled trueresolvePromise(promise, y, resolve, reject)},r {if (called) returncalled truereject(r)})} catch (e) {if (called) returncalled truereject(e)}} else {resolve(x)}} else {resolve(x)} }测试 安装官方测试用例 promises-aplus-tests。 npm i promises-aplus-tests -Dpromise代码中新增以下。 // promise.js class Promise {... }Promise.deferred () {const result {}result.promise new Promise((resolve, reject) {result.resolve resolveresult.reject reject})return result }module.exports Promise新增测试命令。 // package.json {...scripts: {test: promises-aplus-tests promise.js},...devDependencies: {promises-aplus-tests: ^2.1.2} }运行npm run test。 小结 全文共计两万五千字有余参考Promise/A规范手写了then方法和promise解决程序。 相关代码可参考 promise-coding 仓库支持node和浏览器环境测试。 如何手写Promise到此就结束了。 扩展 学有余力或意犹未尽的伙伴们。 贴出两个代码片段可在原生Promise与手写Promise环境下运行。 // 1 new Promise(resolve {resolve(Promise.resolve()) }).then(() {console.log(3) })Promise.resolve().then(() {console.log(1)}).then(() {console.log(2)}).then(() {console.log(4)})// 2 Promise.resolve().then(() {console.log(0)return Promise.resolve()}).then(() {console.log(4)})Promise.resolve().then(() {console.log(1)}).then(() {console.log(2)}).then(() {console.log(3)}).then(() {console.log(5)}).then(() {console.log(6)})看看能否分析出两者之间的细微差异答案是不能。 更多请持续关注更文或在参考链接中探索一二。 参考 Promise/A 规范译文原生 Promise 和手写 Promise 的区别是什么resolve 时序V8 源码解读 Promise 写在最后 伙伴们如果你已经看到了这里觉得这篇文章有帮助到你的话不妨点赞或 Star ✨支持一下哦 手动码字如有错误欢迎在评论区指正~ 你的支持就是我更新的最大动力~ GitHub / Gitee、GitHub Pages、掘金、CSDN 同步更新欢迎关注~
http://www.dnsts.com.cn/news/17481.html

相关文章:

  • 腾讯云做淘客网站唐山网站建设找汉狮
  • 电商网站开发设计方法centos7 wordpress 安装
  • 建设网站需要什么手续wordpress黑客
  • 事业单位门户网站建设包含内容商城网站怎么做seo
  • 邢台市做网站电话灯笼怎么做手工制作视频
  • 手机网站自适应布局怎么做谷德设计网官网首页
  • 朔州企业网站建设公司西安市做网站
  • 做网站需要哪些人才wordpress wpfooter
  • 免费手机h5模板网站模板下载网站标题有图片要怎么做
  • 手机网站建设的背景自贸区注册公司有什么优势
  • 专业建设英文网站微信公众号做视频网站吗
  • 做设计找图片的网站有哪些wordpress 安装平台
  • 重庆电力建设公司网站企业网络构建
  • 江苏seo推广seo网上培训多少钱
  • 网站psd下载word可以制作网页
  • 货源网站网店设计教程
  • 备案号 不放在网站首页免费 网站
  • 广州网站设计服务商东莞常平招聘网最新招聘信息
  • 做网站背景企业网络安全管理制度和应急预案
  • 检查网站打开速度怎么自己做网站地图
  • 官方网站下载cad后台很慢wordpress
  • 新乡微网站建设百度指数明星人气榜
  • 虹口免费网站制作注册新公司流程
  • nas做流媒体网站网站搜索功能模块
  • 婚纱摄影网站的设计与实现论文河南智慧团建网站登录
  • joomla做类似赶集网的网站陕西营销型手机网站
  • 网站设计规划书怎么写公司网站的具体步骤
  • 温州建设局网站wordpress+adsense主题
  • 山东建设和城乡建设厅注册中心网站首页dedecms网站如何上线
  • 做的网站缩小内容就全乱了网页制作基础考什么