var result = tryCatch(tryToUnwrap); if (result.status === 'error') { onError(result.value); } }
// 还有一个很重要的handlers全局对象的定义,如下所示: var handlers = {}; handlers.resolve = function (self, value) { var result = tryCatch(getThen, value); if (result.status === 'error') { return handlers.reject(self, result.value); } var thenable = result.value;
if (thenable) { safelyResolveThenable(self, thenable); } else { self.state = FULFILLED; // FULFILLED 的值是一个数组["fulfilled"] self.outcome = value; var i = -1; var len = self.queue.length; while (++i < len) { self.queue[i].callFulfilled(value); } } return self; }; handlers.reject = function (self, error) { self.state = REJECTED; // REJECTED 的值是一个数组["rejected"] self.outcome = error; var i = -1; var len = self.queue.length; while (++i < len) { self.queue[i].callRejected(error); } return self; };
functiongetThen(obj) { // Make sure we only access the accessor once as required by the spec var then = obj && obj.then; if (obj && (typeof obj === 'object' || typeof obj === 'function') && typeof then === 'function') { returnfunctionappyThen() { then.apply(obj, arguments); }; } }
var Mutation = global.MutationObserver || global.WebKitMutationObserver;
var scheduleDrain;
{ if (Mutation) { var called = 0; var observer = new Mutation(nextTick); var element = global.document.createTextNode(''); observer.observe(element, { characterData: true }); scheduleDrain = function () { // 每次调用scheduleDrain都会改变element,而element是被监视了的,所以此时nextTick会被触发,属于微观层面的异步行为 element.data = (called = ++called % 2); }; } elseif (!global.setImmediate && typeof global.MessageChannel !== 'undefined') { var channel = new global.MessageChannel(); channel.port1.onmessage = nextTick; scheduleDrain = function () { channel.port2.postMessage(0); }; } elseif ('document'in global && 'onreadystatechange'in global.document.createElement('script')) { scheduleDrain = function () {
// Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted // into the document. Do so, thus queuing up the task. Remember to clean up once it's been called. var scriptEl = global.document.createElement('script'); scriptEl.onreadystatechange = function () { nextTick(); scriptEl.onreadystatechange = null; scriptEl.parentNode.removeChild(scriptEl); scriptEl = null; }; global.document.documentElement.appendChild(scriptEl); }; } else { scheduleDrain = function () { setTimeout(nextTick, 0); }; } }