Skip to content

Instantly share code, notes, and snippets.

@dondevi
Last active June 28, 2018 12:16
Show Gist options
  • Save dondevi/1ce5d32e2639b8d7ce774c26a308603e to your computer and use it in GitHub Desktop.
Save dondevi/1ce5d32e2639b8d7ce774c26a308603e to your computer and use it in GitHub Desktop.
/**
* Promises/A+
* @see http://www.ituring.com.cn/article/66566
* @param {Function} executor
*/
function MyPromise (executor) {
let PromiseStatus = "pending";
let PromiseValue = undefined;
let PromiseTasks = [];
const storeTask = task => {
PromiseTasks.push(task);
};
const excuteTask = task => {
switch (PromiseStatus) {
case "resolved": var { onResolved: handle, resolve: settle } = task; break;
case "rejected": var { onRejected: handle, reject: settle } = task; break;
}
try {
if (handle instanceof Function) {
let value = handle(PromiseValue);
return task.resolve(value);
}
settle(PromiseValue);
} catch (exception) {
task.reject(exception);
}
};
const excutePromise = (status, value) => {
setTimeout(() => {
if ("pending" !== PromiseStatus) { return; }
PromiseStatus = status;
PromiseValue = value;
PromiseTasks.forEach(excuteTask);
});
};
const resolvePromise = value => {
if (value === this) {
let exception = new TypeError("Chaining cycle detected for promise #<Promise>");
return rejectPromise(exception);
}
if (value instanceof Object) {
try {
let { then } = value;
if (then instanceof Function) {
return then.call(value, resolvePromise, rejectPromise);
}
} catch (exception) {
return rejectPromise(exception);
}
}
excutePromise("resolved", value);
};
const rejectPromise = reason => {
excutePromise("rejected", reason);
}
executor && executor(resolvePromise, rejectPromise);
this.then = (onResolved, onRejected) => {
return new MyPromise((resolve, reject) => {
let task = { onResolved, onRejected, resolve, reject };
"pending" === PromiseStatus ? storeTask(task) : excuteTask(task);
});
};
this.catch = onRejected => {
return this.then(undefined, onRejected);
};
this.finally = onFinally => {
let handle = value => onFinally();
return this.then(handle, handle);
};
return this;
}
function test (PromiseObject) {
let p0 = new PromiseObject((resolve, reject) => {
resolve("from resolve");
reject("from reject");
}).catch(error => error).then(value => {
console.log("\n" + PromiseObject.name + ":");
return value;
});
p0.then(value => {
console.log("1-then-1: ", value);
return "from 1-then-1";
}).then(value => {
console.log("1-then-2: ", value);
throw "from 1-then-2";
}).then(value => {
console.log("1-then-3: ", value);
return "from 1-then-3";
}).catch(error => {
console.log("1-catch-1: ", error);
return "from 1-catch-1";
}).then(value => {
console.log("1-always-1: ", value);
return "from 1-always-1";
}).catch(error => {
console.log("1-catch-2: ", error);
return "from 1-catch-2";
}).then(value => {
console.log("1-always-2: ", value);
});
p0.then(value => {
console.log("2-then-1: ", value);
let p1 = new PromiseObject((resolve, reject) => {
setTimeout(() => resolve(p1));
});
return p1;
}).then(value => {
console.log("2-then-2: ", value);
return "from 2-then-2";
}).catch(error => {
console.log("2-catch-1: ", error);
throw "from 2-catch-1";
}).catch(error => {
console.log("2-catch-2: ", error);
return "from 2-catch-2";
});
}
test(Promise);
test(MyPromise);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment