Last active
May 30, 2017 12:11
-
-
Save lqt0223/50dff7bb317aea41764f9557bcdc1529 to your computer and use it in GitHub Desktop.
Promise implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Promise Implemenetation | |
// SOME CONSTANT | |
var https = require('https') | |
var URL1 = "https://jsonplaceholder.typicode.com/posts?userId=" | |
var URL2 = "https://jsonplaceholder.typicode.com/posts?id=" | |
// Phase 1: make function in 'then' deferred, and callback with resolved data later | |
// TEST | |
var timeout = function(ms) { | |
return new _Promise1(function(resolve) { | |
setTimeout(function() { | |
resolve("test data") | |
}, ms) | |
}) | |
} | |
timeout(2000).then(function(data){ | |
console.log(data) | |
}) | |
// IMPLEMENTATION | |
function _Promise1(handler) { | |
this.then = function(deferred){ | |
this.deferred = deferred | |
} | |
handler((data) => { | |
this.deferred(data) | |
}) | |
} | |
// Phase 2: chaining promise, and passing resolved data using return | |
// TEST | |
var get = function(url) { | |
return new _Promise2(function(resolve) { | |
https.get(url, (res) => { | |
var buffer = new Buffer([]) | |
res.on("data", (data) => { | |
buffer = Buffer.concat([buffer, data]) | |
}) | |
res.on("end", () => { | |
resolve(buffer.toString()) | |
}) | |
}) | |
}) | |
} | |
get(URL1 + "2").then(function(data){ | |
var posts = JSON.parse(data) | |
var lastPost = posts[posts.length - 1] | |
var lastId = lastPost.id | |
return lastId | |
}).then(function(id) { | |
get(URL2 + id).then(function(data) { | |
console.log(data) | |
}) | |
}) | |
// IMPLEMENTATION | |
function _Promise2(handler){ | |
this.deferred = [] | |
this.transferred | |
this.then = function(deferred) { | |
this.deferred.push(deferred) | |
return this | |
} | |
handler((data) => { | |
this.transferred = data | |
while(this.deferred.length > 0){ | |
var deferred = this.deferred.shift() | |
this.transferred = deferred(this.transferred) | |
} | |
}) | |
} | |
// Phase 3: pass on Promise object using return and get resolved value in the next then call (with refractoring) | |
// TEST | |
var get = function(url) { | |
return new _Promise3(function(resolve) { | |
https.get(url, (res) => { | |
var buffer = new Buffer([]) | |
res.on("data", (data) => { | |
buffer = Buffer.concat([buffer, data]) | |
}) | |
res.on("end", () => { | |
resolve(buffer.toString()) | |
}) | |
}) | |
}) | |
} | |
get(URL1 + "3").then(function(data){ | |
var posts = JSON.parse(data) | |
var lastPost = posts[posts.length - 1] | |
var lastId = lastPost.id | |
return lastId | |
}) | |
.then(function(id) { | |
return (URL2 + id) | |
}) | |
.then(function(url) { | |
return get(url) | |
}) | |
.then(function(response){ | |
return response.slice(1,200) | |
}) | |
.then(function(sliced) { | |
return sliced.match("\"userId\":.*,")[0] | |
}) | |
.then(function(userId) { | |
return userId.slice(10,-1) | |
}) | |
.then(function(userId) { | |
var newUserId = parseInt(userId) + 2 | |
return get(URL1 + newUserId) | |
}) | |
.then(function(res) { | |
console.log(res) | |
}) | |
// IMPLEMENTATION | |
function _Promise3(handler){ | |
var self = this | |
// the array for deferred callbacks | |
this.deferred = [] | |
// implement a internal resolve function that can resolve a promise object and callback result | |
function _resolve(promise, callback){ | |
promise.then(function(data){ | |
callback(data) | |
}) | |
} | |
// recursively call this to invoke deferred handlers, | |
// and when the passed on value is a promise object, | |
// resolve it before the next deferred handler | |
function resolveDeferred() { | |
if(self.deferred.length == 0) return | |
var deferred = self.deferred.shift() | |
if(isPromise(self.passOn)) { | |
_resolve(self.passOn, function(_data) { | |
self.passOn = deferred(_data) | |
resolveDeferred() | |
}) | |
}else{ | |
self.passOn = deferred(self.passOn) | |
resolveDeferred() | |
} | |
} | |
function getClassName(obj){ | |
var pattern = /function .*\(/ | |
return obj.constructor.toString().match(pattern)[0].slice(9, -1) | |
} | |
function isPromise(object) { | |
if(typeof object != "object") return false | |
var className = getClassName(self) | |
var objClassName = getClassName(object) | |
return className == objClassName | |
} | |
this.then = function(deferred) { | |
this.deferred.push(deferred) | |
return this | |
} | |
// when a new promise object is instantiated, | |
// the handler function will be immediately invoked, | |
// resolve deferred in sequence. | |
handler((data) => { | |
// the variable for data that is passed on by return in 'then' function | |
this.passOn = data | |
resolveDeferred() | |
}) | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment