(function () {
"use strict"
/* 工具 */
var isArray = function isArray(value) {
var type = Object.prototype.toString.call(value)
return /^\[object Array\]$/i.test(type)
}
var isPromise = function isPromise(x) {
if (x == null) return false
if (/^(object|function)$/i.test(typeof x)) {
if (typeof x.then === "function") {
return true
}
}
return false
}
var handle = function handle(promise, x, resolve, reject) {
if (x === promise) throw new TypeError('Chaining cycle detected for promise #<Promise>')
if (isPromise(x)) {
try {
x.then(function (result) {
resolve(result)
}, function (err) {
reject(err)
})
} catch (err) {
reject(err)
}
return
}
resolve(x)
}
/* 核心 */
function Promise(executor) {
var self = this,
change
if (typeof self === "undefined") throw new TypeError('undefined is not a promise')
if (typeof executor !== "function") throw new TypeError('Promise resolver ' + executor + ' is not a function')
self.state = 'pending'
self.result = undefined
self.onFulfilledCallbacks = []
self.onRejectedCallbacks = []
change = function change(state, result) {
if (self.state !== "pending") return
self.state = state
self.result = result
if (self.onFulfilledCallbacks.length === 0 && self.onRejectedCallbacks.length === 0) return
setTimeout(function () {
var i = 0,
callbacks = self.state === "fulfilled" ? self.onFulfilledCallbacks : self.onRejectedCallbacks,
len = callbacks.length,
item
for (
item = callbacks[i]
typeof item === "function" ? item(self.result) : null
}
})
}
try {
executor(function resolve(result) {
change('fulfilled', result)
}, function reject(reason) {
change('rejected', reason)
})
} catch (err) {
change('rejected', err)
}
}
Promise.prototype = {
constructor: Promise,
customer: true,
then: function (onfulfilled, onrejected) {
if (typeof onfulfilled !== "function") {
onfulfilled = function onfulfilled(result) {
return result
}
}
if (typeof onrejected !== "function") {
onrejected = function onrejected(reason) {
throw reason
}
}
var self = this,
promiseNew,
x
promiseNew = new Promise(function (resolve, reject) {
switch (self.state) {
case 'fulfilled':
setTimeout(function () {
try {
x = onfulfilled(self.result)
handle(promiseNew, x, resolve, reject)
} catch (err) {
reject(err)
}
})
break
case 'rejected':
setTimeout(function () {
try {
x = onrejected(self.result)
handle(promiseNew, x, resolve, reject)
} catch (err) {
reject(err)
}
})
break
default:
self.onFulfilledCallbacks.push(function (result) {
try {
x = onfulfilled(result)
handle(promiseNew, x, resolve, reject)
} catch (err) {
reject(err)
}
})
self.onRejectedCallbacks.push(function (reason) {
try {
x = onrejected(reason)
handle(promiseNew, x, resolve, reject)
} catch (err) {
reject(err)
}
})
}
})
return promiseNew
},
catch: function (onrejected) {
var self = this
return self.then(null, onrejected)
}
}
if (typeof Symbol !== "undefined") {
Promise.prototype[Symbol.toStringTag] = 'Promise'
}
Promise.resolve = function resolve(value) {
return new Promise(function (resolve) {
resolve(value)
})
}
Promise.reject = function reject(value) {
return new Promise(function (_, reject) {
reject(value)
})
}
Promise.all = function all(promises) {
var legal = true
typeof Symbol !== "undefined" ? (typeof promises[Symbol.iterator] !== "function" ? legal = false : null) : (!isArray(promises) ? legal = false : null)
if (legal === false) throw new TypeError(promises + ' is not iterable')
return new Promise(function (resolve, reject) {
var i = 0,
len = promises.length,
index = 0,
item,
results = []
for (
(function (i) {
item = promises[i]
if (!isPromise(item)) item = Promise.resolve(item)
item.then(function (result) {
index++
results[i] = result
if (index >= len) resolve(results)
}, reject)
})(i)
}
})
}
/* 暴露API */
if (typeof window !== "undefined") {
window.Promise = Promise
}
if (typeof module === "object" && typeof module.exports === "object") {
module.exports = Promise
}
})()