123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- 'use strict';
- var asap = require('asap')
- module.exports = Promise;
- function Promise(fn) {
- if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new')
- if (typeof fn !== 'function') throw new TypeError('not a function')
- var state = null
- var value = null
- var deferreds = []
- var self = this
- this.then = function(onFulfilled, onRejected) {
- return new self.constructor(function(resolve, reject) {
- handle(new Handler(onFulfilled, onRejected, resolve, reject))
- })
- }
- function handle(deferred) {
- if (state === null) {
- deferreds.push(deferred)
- return
- }
- asap(function() {
- var cb = state ? deferred.onFulfilled : deferred.onRejected
- if (cb === null) {
- (state ? deferred.resolve : deferred.reject)(value)
- return
- }
- var ret
- try {
- ret = cb(value)
- }
- catch (e) {
- deferred.reject(e)
- return
- }
- deferred.resolve(ret)
- })
- }
- function resolve(newValue) {
- try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
- if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.')
- if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
- var then = newValue.then
- if (typeof then === 'function') {
- doResolve(then.bind(newValue), resolve, reject)
- return
- }
- }
- state = true
- value = newValue
- finale()
- } catch (e) { reject(e) }
- }
- function reject(newValue) {
- state = false
- value = newValue
- finale()
- }
- function finale() {
- for (var i = 0, len = deferreds.length; i < len; i++)
- handle(deferreds[i])
- deferreds = null
- }
- doResolve(fn, resolve, reject)
- }
- function Handler(onFulfilled, onRejected, resolve, reject){
- this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null
- this.onRejected = typeof onRejected === 'function' ? onRejected : null
- this.resolve = resolve
- this.reject = reject
- }
- /**
- * Take a potentially misbehaving resolver function and make sure
- * onFulfilled and onRejected are only called once.
- *
- * Makes no guarantees about asynchrony.
- */
- function doResolve(fn, onFulfilled, onRejected) {
- var done = false;
- try {
- fn(function (value) {
- if (done) return
- done = true
- onFulfilled(value)
- }, function (reason) {
- if (done) return
- done = true
- onRejected(reason)
- })
- } catch (ex) {
- if (done) return
- done = true
- onRejected(ex)
- }
- }
|