Title: 手写 Promise 源码实现 · Issue #85 · sisterAn/JavaScript-Algorithms · GitHub
Open Graph Title: 手写 Promise 源码实现 · Issue #85 · sisterAn/JavaScript-Algorithms
X Title: 手写 Promise 源码实现 · Issue #85 · sisterAn/JavaScript-Algorithms
Description: 贴一次我之前写的实现,篇幅太长,这里只贴出实现结果,实现细节可前往 JS 基础之异步(三):Promise源码实现 查看 完整代码实现 // 三种状态 const PENDING = "pending" const FULFILLED = "fulfilled" const REJECTED = "rejected" function MyPromise(callback) { var _this = this _this.currentState = PENDING ...
Open Graph Description: 贴一次我之前写的实现,篇幅太长,这里只贴出实现结果,实现细节可前往 JS 基础之异步(三):Promise源码实现 查看 完整代码实现 // 三种状态 const PENDING = "pending" const FULFILLED = "fulfilled" const REJECTED = "rejected" function MyPromise(callback) { var _t...
X Description: 贴一次我之前写的实现,篇幅太长,这里只贴出实现结果,实现细节可前往 JS 基础之异步(三):Promise源码实现 查看 完整代码实现 // 三种状态 const PENDING = "pending" const FULFILLED = "fulfilled" const REJECTED = "rejected" functio...
Opengraph URL: https://github.com/sisterAn/JavaScript-Algorithms/issues/85
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"手写 Promise 源码实现","articleBody":"贴一次我之前写的实现,篇幅太长,这里只贴出实现结果,实现细节可前往 [JS 基础之异步(三):Promise源码实现](https://github.com/sisterAn/blog/issues/13) 查看\r\n\r\n### 完整代码实现\r\n```js\r\n// 三种状态\r\nconst PENDING = \"pending\"\r\nconst FULFILLED = \"fulfilled\"\r\nconst REJECTED = \"rejected\"\r\nfunction MyPromise(callback) {\r\n var _this = this\r\n _this.currentState = PENDING // Promise当前的状态\r\n _this.value = void 0 // Promise的值\r\n // 用于保存 then 的回调, 只有当 promise\r\n // 状态为 pending 时才会缓存,并且每个实例至多缓存一个\r\n _this.onResolvedCallbacks = [] // Promise resolve时的回调函数集\r\n _this.onRejectedCallbacks = [] // Promise reject时的回调函数集\r\n _this.resolve = function (value) {\r\n if (value instanceof MyPromise) {\r\n // 如果 value 是个 Promise, 递归执行\r\n return value.then(_this.resolve, _this.reject)\r\n }\r\n setTimeout(() =\u003e { // 异步执行,保证顺序执行\r\n if (_this.currentState === PENDING) {\r\n _this.currentState = FULFILLED // 状态管理\r\n _this.value = value\r\n _this.onResolvedCallbacks.forEach(cb =\u003e cb())\r\n }\r\n })\r\n } // resolve 处理函数\r\n _this.reject = function (value) {\r\n setTimeout(() =\u003e { // 异步执行,保证顺序执行\r\n if (_this.currentState === PENDING) {\r\n _this.currentState = REJECTED // 状态管理\r\n _this.value = value\r\n _this.onRejectedCallbacks.forEach(cb =\u003e cb())\r\n }\r\n })\r\n } // reject 处理函数\r\n\r\n // 异常处理\r\n // new Promise(() =\u003e throw Error('error'))\r\n try {\r\n callback(_this.resolve, _this.reject) // 执行callback并传入相应的参数\r\n } catch(e) {\r\n _this.reject(e)\r\n }\r\n}\r\n// then 方法接受两个参数,onFulfilled,onRejected,分别为Promise成功或失败的回调\r\nMyPromise.prototype.then = function(onFulfilled, onRejected) {\r\n var _this = this\r\n // 规范 2.2.7,then 必须返回一个新的 promise\r\n var promise2\r\n // 根据规范 2.2.1 ,onFulfilled、onRejected 都是可选参数\r\n // onFulfilled、onRejected不是函数需要忽略,同时也实现了值穿透\r\n onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value =\u003e value\r\n onRejected = typeof onRejected === 'function' ? onRejected : error =\u003e {throw error}\r\n\r\n if (_this.currentState === FULFILLED) {\r\n // 如果promise1(此处为self/this)的状态已经确定并且为fulfilled,我们调用onFulfilled\r\n // 如果考虑到有可能throw,所以我们将其包在try/catch块中\r\n return promise2 = new MyPromise(function(resolve, reject) {\r\n try {\r\n var x = onFulfilled(_this.value)\r\n // 如果 onFulfilled 的返回值是一个 Promise 对象,直接取它的结果作为 promise2 的结果\r\n resolutionProcedure(promise2, x, resolve, reject)\r\n } catch (err) {\r\n reject(err) // 如果出错,以捕获到的错误作为promise2的结果\r\n }\r\n })\r\n }\r\n // 此处实现与FULFILLED相似,区别在使用的是onRejected而不是onFulfilled\r\n if (_this.currentState === REJECTED) {\r\n return promise2 = new MyPromise(function(resolve, reject) {\r\n try {\r\n var x = onRejected(_this.value)\r\n resolutionProcedure(promise2, x, resolve, reject)\r\n } catch(err) {\r\n reject(err)\r\n }\r\n })\r\n }\r\n if (_this.currentState === PENDING) {\r\n // 如果当前的Promise还处于PENDING状态,我们并不能确定调用onFulfilled还是onRejected\r\n // 只有等待Promise的状态确定后,再做处理\r\n // 所以我们需要把我们的两种情况的处理逻辑做成callback放入promise1(此处即_this/this)的回调数组内\r\n // 处理逻辑和以上相似\r\n return promise2 = new MyPromise(function(resolve, reject) {\r\n _this.onResolvedCallbacks.push(function() {\r\n try {\r\n var x = onFulfilled(_this.value)\r\n resolutionProcedure(promise2, x, resolve, reject)\r\n } catch(err) {\r\n reject(err)\r\n }\r\n })\r\n _this.onRejectedCallbacks.push(function() {\r\n try {\r\n var x = onRejected(_this.value)\r\n resolutionProcedure(promise2, x, resolve, reject)\r\n } catch (err) {\r\n reject(err)\r\n }\r\n })\r\n })\r\n }\r\n\r\n // 规范 2.3\r\n /*\r\n resolutionProcedure函数即为根据x的值来决定promise2的状态的函数\r\n 也即标准中的[Promise Resolution Procedure](https://promisesaplus.com/#point-47)\r\n x 为 promise2 = promise1.then(onFulfilled, onRejected)里onFulfilled/onRejected的返回值\r\n resolve 和 reject 实际上是 promise2 的executor的两个实参,因为很难挂在其他地方,所以一并传过来。\r\n 相信各位一定可以对照标准转换成代码,这里就只标出代码在标准中对应的位置,只在必要的地方做一些解释。\r\n */\r\n function resolutionProcedure(promise2, x, resolve, reject) {\r\n // 规范 2.3.1,x 不能和 promise2 相同,避免循环引用\r\n if (promise2 === x) {\r\n return reject(new TypeError(\"Chaining cycle detected for promise!\"))\r\n }\r\n // 规范 2.3.2\r\n // 如果 x 为 Promise,状态为 pending 需要继续等待否则执行\r\n if (x instanceof MyPromise) {\r\n // 2.3.2.1 如果x为pending状态,promise必须保持pending状态,直到x为fulfilled/rejected\r\n if (x.currentState === PENDING) {\r\n x.then(function(value) {\r\n // 再次调用该函数是为了确认 x resolve 的\r\n // 参数是什么类型,如果是基本类型就再次 resolve\r\n // 把值传给下个 then\r\n resolutionProcedure(promise2, value, resolve, reject)\r\n }, reject)\r\n } else { // 但如果这个promise的状态已经确定了,那么它肯定有一个正常的值,而不是一个thenable,所以这里可以取它的状态\r\n x.then(resolve, reject)\r\n }\r\n return\r\n }\r\n\r\n let called = false\r\n // 规范 2.3.3,判断 x 是否为对象或函数\r\n if (x !== null \u0026\u0026 (typeof x === \"object\" || typeof x === \"function\")) {\r\n // 规范 2.3.3.2,如果不能取出 then,就 reject\r\n try {\r\n // 规范2.3.3.1 因为x.then可能是一个getter,这种情况下多次读取就有可能产生副作用\r\n // 既要判断它的类型,又要调用它,这就是两次读取\r\n let then = x.then\r\n // 规范2.3.3.3,如果 then 是函数,调用 x.then\r\n if (typeof then === \"function\") {\r\n // 规范 2.3.3.3\r\n // reject 或 reject 其中一个执行过的话,忽略其他的\r\n then.call(\r\n x,\r\n y =\u003e { // 规范 2.3.3.3.1\r\n if (called) return // 规范 2.3.3.3.3,即这三处谁先执行就以谁的结果为准\r\n called = true\r\n // 规范 2.3.3.3.1\r\n return resolutionProcedure(promise2, y, resolve, reject)\r\n },\r\n r =\u003e {\r\n if (called) return // 规范 2.3.3.3.3,即这三处谁先执行就以谁的结果为准\r\n called = true\r\n return reject(r)\r\n }\r\n )\r\n } else {\r\n // 规范 2.3.3.4\r\n resolve(x)\r\n }\r\n } catch (e) { // 规范 2.3.3.2\r\n if (called) return // 规范 2.3.3.3.3,即这三处谁先执行就以谁的结果为准\r\n called = true\r\n return reject(e)\r\n }\r\n } else {\r\n // 规范 2.3.4,x 为基本类型\r\n resolve(x)\r\n }\r\n }\r\n}\r\n// catch 的实现\r\nMyPromise.prototype.catch = function (onRejected) {\r\n return this.then(null, onRejected)\r\n}\r\n// finally 的实现\r\nMyPromise.prototype.finally = function (callback) {\r\n return this.then(function (value) {\r\n return MyPromise.resolve(callback()).then(function () {\r\n return value\r\n })\r\n }, function (err) {\r\n return MyPromise.resolve(callback()).then(function () {\r\n throw err\r\n })\r\n })\r\n}\r\n// race\r\nMyPromise.race = function(values) {\r\n return new MyPromise(function(resolve, reject) {\r\n values.forEach(function(value) {\r\n MyPromise.resolve(value).then(resolve, reject)\r\n })\r\n })\r\n}\r\n// all\r\nMyPromise.all = function(arr) {\r\n var args = Array.prototype.slice.call(arr)\r\n return new MyPromise(function (resolve, reject) {\r\n if (args.length === 0) return resolve([])\r\n var remaining = args.length\r\n for (var i = 0; i \u003c args.length; i++) {\r\n res(i, args[i])\r\n }\r\n function res(i, val) {\r\n if (val \u0026\u0026 (typeof val === 'object' || typeof val === 'function')) {\r\n if (val instanceof MyPromise \u0026\u0026 val.then === MyPromise.prototype.then) {\r\n if (val.currentState === FULFILLED) return res(i, val.value)\r\n if (val.currentState === REJECTED) reject(val.value)\r\n val.then(function (val) {\r\n res(i, val)\r\n }, reject)\r\n return\r\n } else {\r\n var then = val.then\r\n if (typeof then === 'function') {\r\n var p = new MyPromise(then.bind(val))\r\n p.then(function(val) {\r\n res(i, val)\r\n }, reject)\r\n return\r\n }\r\n }\r\n }\r\n args[i] = val\r\n if (--remaining === 0) {\r\n resolve(args)\r\n }\r\n }\r\n })\r\n}\r\n// allSettled\r\nMyPromise.allSettled = function (promises) {\r\n return new MyPromise((resolve, reject) =\u003e {\r\n promises = Array.isArray(promises) ? promises : []\r\n let len = promises.length\r\n const argslen = len\r\n // 如果传入的是一个空数组,那么就直接返回一个resolved的空数组promise对象\r\n if (len === 0) return resolve([])\r\n // 将传入的参数转化为数组,赋给args变量\r\n let args = Array.prototype.slice.call(promises)\r\n // 计算当前是否所有的 promise 执行完成,执行完毕则resolve\r\n const compute = () =\u003e {\r\n if(--len === 0) { \r\n resolve(args)\r\n }\r\n }\r\n function resolvePromise(index, value) {\r\n // 判断传入的是否是 promise 类型\r\n if(value instanceof MyPromise) { \r\n const then = value.then\r\n then.call(value, function(val) {\r\n args[index] = { status: 'fulfilled', value: val}\r\n compute()\r\n }, function(e) {\r\n args[index] = { status: 'rejected', reason: e }\r\n compute()\r\n })\r\n } else {\r\n args[index] = { status: 'fulfilled', value: value}\r\n compute()\r\n }\r\n }\r\n \r\n for(let i = 0; i \u003c argslen; i++){\r\n resolvePromise(i, args[i])\r\n }\r\n })\r\n }\r\n```","author":{"url":"https://github.com/sisterAn","@type":"Person","name":"sisterAn"},"datePublished":"2020-07-19T15:40:58.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/85/JavaScript-Algorithms/issues/85"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:f76510c1-624a-287b-f7ac-70e951e0384b |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 8924:1CEAED:1C3C00F:2542B83:696AF76D |
| html-safe-nonce | 65fed72d3e4c37850a2442e83e98a92271b334ef90b05f06d488c6f18fa90170 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4OTI0OjFDRUFFRDoxQzNDMDBGOjI1NDJCODM6Njk2QUY3NkQiLCJ2aXNpdG9yX2lkIjoiODMxMjM1NTU2NDcxMjI5NDI1MyIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 5b92f50cc2a7e1b9c141174fb386c1ba936503bc53855dc083b7663593e4b320 |
| hovercard-subject-tag | issue:660905954 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/sisterAn/JavaScript-Algorithms/85/issue_layout |
| twitter:image | https://opengraph.githubassets.com/3bb9321ea3faf969482f737e0493caa9e9d7ff4f81149f530ef2a40562eb92c6/sisterAn/JavaScript-Algorithms/issues/85 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/3bb9321ea3faf969482f737e0493caa9e9d7ff4f81149f530ef2a40562eb92c6/sisterAn/JavaScript-Algorithms/issues/85 |
| og:image:alt | 贴一次我之前写的实现,篇幅太长,这里只贴出实现结果,实现细节可前往 JS 基础之异步(三):Promise源码实现 查看 完整代码实现 // 三种状态 const PENDING = "pending" const FULFILLED = "fulfilled" const REJECTED = "rejected" function MyPromise(callback) { var _t... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | sisterAn |
| hostname | github.com |
| expected-hostname | github.com |
| None | 5f99f7c1d70f01da5b93e5ca90303359738944d8ab470e396496262c66e60b8d |
| turbo-cache-control | no-preview |
| go-import | github.com/sisterAn/JavaScript-Algorithms git https://github.com/sisterAn/JavaScript-Algorithms.git |
| octolytics-dimension-user_id | 19721451 |
| octolytics-dimension-user_login | sisterAn |
| octolytics-dimension-repository_id | 252061924 |
| octolytics-dimension-repository_nwo | sisterAn/JavaScript-Algorithms |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 252061924 |
| octolytics-dimension-repository_network_root_nwo | sisterAn/JavaScript-Algorithms |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 82560a55c6b2054555076f46e683151ee28a19bc |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width