代碼執行順序
const first = () =>
new Promise((resolve, reject) => {
resolve(2);
console.log(3);
let p = new Promise((resolve, reject) => {
console.log(7);
resolve(1);
})
p.then(arg => {
console.log(arg);
})
})
first().then(arg => {
console.log(arg);
})
console.log(4);
複製代碼
Promise構造函數
function Promise(resolver) {
if (typeof resolver !== 'function') {
throw new TypeError('resolver must be a function');
}
this.state = PENDING;
this.queue = [];
this.outcome = void 0;
if (resolver !== INTERNAL) {
safelyResolveThenable(this, resolver);
}
}
複製代碼
- 執行first()
- new Promise進入構造函數
- 執行safelyResolveThenable
function safelyResolveThenable(self, thenable) {
var called = false;
function onError(value) {
if (called) {
return;
}
called = true;
handlers.reject(self, value);
}
function onSuccess(value) {
if (called) {
return;
}
called = true;
handlers.resolve(self, value);
}
function tryToUnwrap() {
thenable(onSuccess, onError);
}
var result = tryCatch(tryToUnwrap);
if (result.status === 'error') {
onError(result.value);
}
}
複製代碼
- 實際執行
tryToUnwrap
的thenable(onSuccess, onError);
thenable
= 當初Promise傳入的如下代碼
(resolve, reject) => {
resolve(2);
console.log(3);
let p = new Promise((resolve, reject) => {
console.log(7);
resolve(1);
})
p.then(arg => {
console.log(arg);
})
}
複製代碼
- 執行
resolve(2)
- 即執行
function onSuccess(value) {
if (called) {
return;
}
called = true;
// value = 2
handlers.resolve(self, value);
}
複製代碼
- handlers.resolve
handlers.resolve = function (self, value) {
// 每次執行都過tryCatch,這也是爲何能最後Catch到的緣由
var result = tryCatch(getThen, value);
if (result.status === 'error') {
return handlers.reject(self, result.value);
}
var thenable = result.value;
// thenable = undefined
if (thenable) {
safelyResolveThenable(self, thenable);
} else {
// 進入這裏
self.state = FULFILLED;
// outcome記錄2
self.outcome = value;
var i = -1;
// self.queue = []
var len = self.queue.length;
// 沒有執行的
while (++i < len) {
self.queue[i].callFulfilled(value);
}
}
return self;
};
複製代碼
- 同樣的執行順序
- 打印7,執行resolve(1);
- getThen(這步返回undefined),與本題無關
function getThen(obj) {
// Make sure we only access the accessor once as required by the spec
var then = obj && obj.then;
// 判斷傳入參數是否是Promise
if (obj && (typeof obj === 'object' || typeof obj === 'function') && typeof then === 'function') {
return function appyThen() {
then.apply(obj, arguments);
};
}
}
複製代碼
- then
Promise.prototype.then = function (onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function' && this.state === FULFILLED ||
typeof onRejected !== 'function' && this.state === REJECTED) {
return this;
}
// 新生成Promise
var promise = new this.constructor(INTERNAL);
// this.state = "FULFILLED"
if (this.state !== PENDING) {
// 進入這裏resolver = onFulfilled
var resolver = this.state === FULFILLED ? onFulfilled : onRejected;
// this.outcome = 1, promise = 新構造的
unwrap(promise, resolver, this.outcome);
} else {
this.queue.push(new QueueItem(promise, onFulfilled, onRejected));
}
return promise;
};
複製代碼
- unwrap
function unwrap(promise, func, value) {
// task = immediate裏面的funciton
immediate(function () {
var returnValue;
try {
returnValue = func(value);
} catch (e) {
return handlers.reject(promise, e);
}
if (returnValue === promise) {
handlers.reject(promise, new TypeError('Cannot resolve promise with itself'));
} else {
handlers.resolve(promise, returnValue);
}
});
}
複製代碼
immediate.js
var Mutation = global.MutationObserver || global.WebKitMutationObserver;
var called = 0;
var observer = new Mutation(nextTick);
var element = global.document.createTextNode('');
observer.observe(element, {
characterData: true
});
scheduleDrain = function () {
element.data = (called = ++called % 2);
};
function immediate(task) {
if (queue.push(task) === 1 && !draining) {
scheduleDrain();
}
}
var draining;
var queue = [];
function nextTick() {
draining = true;
var i, oldQueue;
var len = queue.length;
while (len) {
oldQueue = queue;
queue = [];
i = -1;
while (++i < len) {
oldQueue[i]();
}
len = queue.length;
}
draining = false;
}
複製代碼
- immediate
// 當queue = [], draining = undefined
function immediate(task) {
if (queue.push(task) === 1 && !draining) {
scheduleDrain(); // 執行scheduleDrain
}
}
複製代碼
- scheduleDrain執行
- 執行first().then
- 再次執行14步驟,可是隻push,不執行裏面的scheduleDrain
- 而後打印console.log(4);
- 如今執行nextTick回調
- 按照先進先出,打印1,2