Skip to content

jasonleft/iPromise

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

74 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

iPromise v0.8.2

iPromise is a standalone async library which implements the Promises/A+. Async codes are confusing because you will dump into the callback hell easily. iPromise improves the readability of async codes by saving us from the hell.

###In This Documentation 1. Tutorial
2. API
 Constructor
iPromise(mixin, arg)
 Instance Methods
iPromise#then(fulfilledFn, rejectedFn, finallyFn)
iPromise#catch(rejectedFn, finallyFn)
iPromise#wait(ms)
 Function Properties
iPromise.resolve(val)
iPromise.reject(reason)
iPromise.all(condition)
iPromise.any/race(condition)
iPromise.wait(ms, arg)
3. Changelog
4. Referrence

Tutorial

###1. Build your own production-ready code.

> git clone https://github.com/fsjohnhuang/iPromise.git
> cd iPromise
> npm install
> npm run build

###2. Include iPromise on your site. Compiled and production-ready code can be found in the dist directory.Then src directory contains development code. Unit tests are located in the test directory.

<script src="dist/iPromise.min.js"></script>
<script src="myapp.js"></script>

###3. Comparision with ordinary callback processes Now we want to do some amazing animation effection by ordinary callback process.

var el = document.getElementById('box')
var xy = {x: el.offsetLeft, y: el.offsetTop}
setTimeout(function(){
  xy.x = xy.x + 100 
  el.style.left =  xy.x + 'px'

  setTimeout(function(){
    xy.x = xy.x + 100 
    el.style.left =  xy.x + 'px'

    setTimeout(function(){
      xy.x = xy.x + 200 
      el.style.left =  xy.x + 'px'
    }, 500)
  }, 500)
}, 500)

iPromise save our time.

var el = document.getElementById('box')
var xy = {x: el.offsetLeft, y: el.offsetTop}
iPromise
  .wait(500)
  .then(function(){
    xy.x = xy.x + 100 
    el.style.left =  xy.x + 'px'
  })
  .wait(500)
  .then(function(){
    xy.x = xy.x + 100 
    el.style.left =  xy.x + 'px'
  })
  .wait(500)
  .then(function(){
    xy.x = xy.x + 200 
    el.style.left =  xy.x + 'px'
  })

API

###Constructor ####iPromise(mixin, arg) @description Create new iPromise object.
@param {(Function.<Function fulfilledFn,Function rejectedFn>|GeneratorFunction)} mixin - Factory function to change the status of iPromise object. Or a Generator Function(feature by ES6).
@param {...*} arg - It would be work when mixin is an instanceof GeneratorFunction.
@return {?iPromise} - The returns would be undefined when mixin is an instanceof GeneratorFunction.

/* mixin is function */
var p2 = iPromise(function(resolve, reject){
  setTimeout(function(){
    resolve('hello', 'world', '!')
  }, 5000)
})

/* mixin is generator function */
iPromise(function *(name, city){
  console.log('Welcome to ' + city)

  var msg
  try{
    msg = yield wrapMsg(name)
  }
  catch(e){
    msg = 'Hi, ' + name
  }
  console.log(msg)
}, 'fsjohnhuang', 'fs')

###Instance Methods ####iPromise#then(fulfilledFn, rejectedFn, finallyFn) @description Subscribes the iPromise object's status changed event.
@param {Function.<*>} fulfilledFn - It would be called when iPromise object's status is from pending to fulfilled
@param {Function.<*>} rejectedFn - It would be called when iPromise object's status is from pending to rejected
@param {Function.<*>} finallyFn - It would be called when iPromise object's status is changed and has subscribed fulfilled or rejected status changing event
@return {iPromise} - The subset of iPromise object which contains iPromise#then, iPromise#catch and iPromise#wait only.

iPromise(function(resolve, reject){
    resolve()
  })
  .then(function(){
    console.log('from pending to fulfilled')
  }, function(){
    console.log('from pending to rejected')
  }, function(){
    console.log('finally')
  })

####iPromise#catch(rejectedFn, finallyFn) @description Subscribes the iPromise object's status changed event which is from pending to rejected.
@param {Function.<*>} rejectedFn - It would be called when iPromise object's status is from pending to rejected
@param {Function.<*>} finallyFn - It would be called when iPromise object's status is changed and has subscribed rejected status changing event
@return {iPromise} - The subset of iPromise object which contains iPromise#then, iPromise#catch and iPromise#wait only.

iPromise(function(resolve, reject){
    reject() 
  })
  .catch(function(){
    console.log('from pending to rejected')
  }, function(){
    console.log('finally')
  })

####iPromise#wait(ms) @description Invokes the next callback function after ms milliseconds without changing the status of iPromise object.
@param {number} ms - The time to wait.
@return {iPromise} - The subset of iPromise object which contains iPromise#then, iPromise#catch and iPromise#wait only.

iPromise(function(resolve, reject){
    resolve()
  })
  .then(function(arg){
    return +new Date()
  })
  .wait(1000)
  .then(function(arg){
    console.log((+new Date()) - arg > 1000) // true
  })

###Function Properties ####iPromise.resolve(val) @description Change the status of iPromise object from pending to fulfilled.
@param {*} val - It would be as the argument of fulfilled callback function which is invoked first.

/* arg is such as ({*} arg) */
iPromise
  .resolve(1)
  .then(function(arg){
    console.log(arg)
  })

/* arg is such as ({Thenable} arg) */
iPromise
  .resolve({then:function(resolve){resolve('test')}})
  .then(function(arg){
    console.log(arg)
  })

####iPromise.reject(reason) @description Change the status of iPromise object from pending to rejected.
@param {*} arg - It would be as the argument of rejected callback function which is invoked first.

/* arg is such as ({*} arg) */
iPromise
  .reject(1)
  .then(null, function(arg){
    console.log(arg)
  })

/* arg is such as ({Thenable} arg) */
iPromise
  .reject({then:function(resolve){resolve('test')}})
  .then(function(arg){
    console.log(arg)
  })

####iPromise.all(condition) @description Change the status of iPromise object from pending to fulfilled when meets all conditions, otherwise would change status from pending to rejected
@param {...*} condition
@return {iPromise} - The subset of iPromise object which contains iPromise#then, iPromise#catch and iPromise#wait only.

a = 1
b = iPromise(function(r){
  setTimeout(function(){r(2)}, 200)
})
c = {
  then: function(r){
    setTimeout(function(){r(3)}, 600)
  }
}
var curr, o = +new Date() 
iPromise.all(a,b,c).then(function(val){
  curr = +new Date()
  console.log(curr - o > 600) // true
}

####iPromise.any(condition) / iPromise.race(condition) @description Change the status of iPromise object from pending to fulfilled when meets any condition, otherwise would change status from pending to rejected
@param {...*} condition
@return {iPromise} - The subset of iPromise object which contains iPromise#then, iPromise#catch and iPromise#wait only.

a = iPromise(function(r){
  setTimeout(function(){r(2)}, 200)
})
c = {
  then: function(r){
    setTimeout(function(){r(3)}, 600)
  }
}
var curr, o = +new Date() 
iPromise.all(b,c).then(function(val){
  curr = +new Date()
  console.log(curr - o < 300) // true
}

####iPromise.wait(ms, arg) @description Changes the status of iPromise object from pending to fulfilled after ms milliseconds.
@param {number} ms - The time to wait.
@param {...*} arg - Is would be arguments of the next fulfilled callback function.
@return {iPromise} - The subset of iPromise object which contains iPromise#then, iPromise#catch and iPromise#wait only.

iPromise
  .wait(1000, +new Date())
  .then(function(arg){
    console.log((+new Date()) - arg > 1000) // true
  })

##Changelog ###v0.8.2 bug修复

  1. 修复后iPromise.resolve({Thenable})iPromise.reject({Thenable})方法均可将一个thenable对象转换为iPromise对象

###v0.8.1 bug修复

  1. 修复重复调用resolve或reject方法时,会覆盖之前的val和reason值的问题。现在无论调用多少次resovle或reject方法,均只有第一次调用是有效的。

###v0.8.0 全局重构

  1. 改用事件机制订阅iPromise状态变化事件从而触发相应的处理函数。
    事件机制由*TinyES(迷你事件系统模块)AsyncES(事件异步响应系统模块)*两个模块提供
  2. 删除实例方法resolve和reject。
  3. 新增类方法resolve和reject。

###v0.7.0 全局重构
新增

  1. utils模块,将原来位于iPromise模块中的辅助函数迁移到utils模块中。
    修改
  2. then({Function} fulfilledFn,{Function} rejectedFn,{Function} progressFn,{Function} finallyFn)-->then({Function} fulfilledFn,{Function} rejectedFn,{Function} finallyFn)
  3. catch({Function} rejectedFn)-->catch({Function} rejectedFn,{Function} finallyFn)
  4. iPromise.wait({Number} ms)-->iPromise.wait({Number} ms/*, ...args*/)
    删除
  5. notify()
  6. finally()

###v0.6.1 添加mocha、chai作为单元测试套件
添加blanket作为覆盖率测试库
添加npm作为依赖管理工具

###v0.6.0 bug修复

  1. #20141217 iPromise({Function} mixin),没有捕获mixin内部抛出同步异常->捕获mixin内部抛出同步异常,并将异常信息作为入参调用deferred实例的reject函数。
  2. iPromise({Function|Object} mixin?),若mixin为Object,则返回的为deferred实例,若mixin为Function,则返回的是Promise实例。
    新特性
  3. iPromise构造器接受ES6的Generator Function。并返回undefined
var getData = function(dataSrc){
  return iPromise(function(r){
  	setTimeout(function(){
  		r(dataSrc + ' has loaded')
  	}, 1000)
  })
}
var getTpl = function(tplSrc){
  return iPromise(function(r){
  	setTimeout(function(){
  		r(tplStr + ' has loaded')
  	}, 2000)
  })
}
var render = function(data, tpl){
	throw new Error('OMG!')
}
iPromise(function *(dataSrc, tplSrc){
  try{
  	var data = yield getData(dataSrc)
  	var tpl = yield getTpl(tplSrc)
  	render(data, tpl)
  }
  catch(e){
  	console.log(e)
  }
  console.log('over!')
}, 'dummyData.json', 'dummyTpl.json')
/* 结果如下 */
// 等待1秒多显示 dummyData.json has loaded
// 等待2秒多显示 dummyTpl.json has loaded
// 显示 Error: OMG!
//     Stack trace:
//     test10/render/</<@file:///home/fsjohnhuang/repos/iPromise/test/v0.0.2.html:190:6
// 显示 over!

###v0.5.0 新特性

  1. 新增{Promise} wait({number} ms){Promise} iPromise.wait({number} ms),等待ms毫秒在执行后续的回调函数,此方法不会改变Deferred实例状态和责任链传递的值。

##v0.4.0 bug修复

  1. #20141215 可重复添加回调函数->仅能添加一次回调函数
    新特性
  2. 新增APIiPromise.all([Object|Array}|...[*]), 当所有入参均成功返回值时则执行成功回调函数
var thenable = {
  then: function(r){
  	setTimeout(function(){
  		r('hi', 'there')
  	}, 1000)
  }
}
var name = 'fsjohnhuang'
var promise1 = iPromise(function(r){
  	setTimeout(function(){
  		r('I\'m')
  	}, 2000)
})
iPromise.all(thenable, name, promise1).then(function(arg){
	alert(arg[0][0] + ' ' + arg[0][1] + ',' + arg[2] + ' ' + arg[1]) // 两秒多后显示hi there,I'm fsjohnhuang
})
iPromise.all([thenable, name, promise1]).then(function(arg){
	alert(arg[0][0] + ' ' + arg[0][1] + ',' + arg[2] + ' ' + arg[1]) // 两秒多后显示hi there,I'm fsjohnhuang
})
iPromise.all({a:thenable, b:name, c:promise1}).then(function(arg){
	alert(arg.a[0] + ' ' + arg.a[1] + ',' + arg.c + ' ' + arg.b) // 两秒多后显示hi there,I'm fsjohnhuang
})
  1. 新增APIiPromise.any([Object|Array}|...[*]),当有一个入参成功返回时则执行成功回调函数
var thenable = {
  then: function(r){
  	setTimeout(function(){
  		r('hi', 'there')
  	}, 1000)
  }
}
var name = 'fsjohnhuang'
var promise1 = iPromise(function(r){
  	setTimeout(function(){
  		r('I\'m')
  	}, 2000)
})
iPromise.all(thenable, name, promise1).then(function(arg){
	alert(arg) // 显示fsjohnhuang
})
iPromise.all([thenable, name, promise1]).then(function(arg){
	alert(arg) // 显示fsjohnhuang
})
iPromise.all({a:thenable, b:name, c:promise1}).then(function(arg){
	alert(arg) // 显示fsjohnhuang
})

###v0.3.0 新特性

  1. 支持上一个resolveFn或rejectFn函数返回值为Promise对象时,晚绑定的resolveFn或rejectFn均可以该Promise对象作为入参被执行。
var deferred = iPromise(function(resolve){
	resolve()
})
var promise = deferred.then(function(){
	return new iPromise(function(resolve){
		resolve('hello', 'world')
	})	
})
// 一秒多后显示hello world
setTimeout(function(){
	promise.then(function(arg1, arg2){
		alert(arg1 + ' ' + arg2)	
	})	
}, 1000)
  1. 支持上一个resolveFn或rejectFn函数返回值为thenable对象时,晚绑定的resolveFn或rejectFn均可以该Promise对象作为入参被执行。
var deferred = iPromise(function(resolve){
	resolve()
})
var promise = deferred.then(function(){
	var thenable = {
		then: function(resolve){
			resolve('hello', 'world')
		}
	}	
	return thenable
})
// 一秒多后显示hello world
setTimeout(function(){
	promise.then(function(arg1, arg2){
		alert(arg1 + ' ' + arg2)	
	})	
}, 1000)

###v0.2.0 全局重构,API说明

  1. {Deferred} [new] iPromise({Object|Function<this:null,{Function} resovle, {Function} reject, {Function} notify>}),构造Deferred实例,入参为Object类型时则将入参的属性和方法附加到返回的Deferred实例上,若入参为函数则可在函数体内调用resolve、reject或notify方法触发调用Deferred实例的回调函数的请求。
  2. {Promise} then({Function} resolveFn?, {Function} rejectFn?, {Function} progressFn?, {Function} finally?),向Deferred实例添加四类回调函数。
  3. {Promise} catch({Function} rejectFn?),向Deferred实例添加rejected状态的回调函数,仅能执行一次。
  4. {Promise} progress({Function} progressFn?),向Deferred实例添加可以多次执行的回调函数
  5. {Promise} finally{Function} finallyFn?),向Deferred实例添加模拟finally语句的回调函数,在调用resovle和reject函数时必定会执行该函数,并且当该函数抛异常时会将当前Deferred的状态设置为rejected
  6. resolve(...[*])
  7. reject(...[*])
  8. notify(...[*])

特性

  1. iPromise包含Deferred和Promise两类操作集合,其中Promise是Deferred的子集,仅提供添加回调函数的功能。而Deferred集合还提供发起执行回调函数请求的功能。
  2. 回调函数支持任意数目的入参。
  3. resolveFn和rejectFn函数支持晚绑定。
var deferred = iPromise(function(resolve){
	resolve('hello', 'world')
})
setTimeout(function(){
	deferred.then(function(arg1, arg2){
		alert(arg1 + ' ' + arg2) // 一秒多后,显示hello world
	})
}, 1000)

###v0.1.0 实现基础接口API

  1. new iPromise([fn(resolve, reject)]),构造promise实例,可传入一个带resolve函数、reject函数的入参方法。
  2. then([{Function} fulfilledHandler[, {Function} rejectedHandler]]),重写fulfilled和rejected回调。
  3. resolve([{Any} data]),promise实例方法,用于触发fulfilled回调。
  4. reject([{Any} data]),promise实例方法,用于触发rejected回调。

##Referrence prmises/A+
prmises/A
JavaScript异步编程的模式
深入理解Promise五部曲

About

An implementation for promises/A+

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 90.4%
  • HTML 8.4%
  • Other 1.2%