Promise 对象用于延迟(deferred) 计算和异步(asynchronous ) 计算。一个Promise对象表明着一个还未完成,但预期未来会完成的操做。app
先来一个例子 A 熟悉下语法异步
var p = new Promise(function(resolve, reject){ console.log('1'); // 运行后续的 callback 列表,例如:then,when等。不然,不会执行then里面的函数 resolve('go next'); }); // 只考虑成功 p.then(function(){ console.log(2, arguments); return 'next'; }, null).then(function(){ console.log(3, arguments) }, null); // 输出 1 2 ['go next'] 3 ['next']
最初的设想async
function Promise(func){ // 接收一个函数做为参数 } Promise.prototype = { then: function(callback){ // 接收函数做为参数 return this; // 支持链式调用 } }
观察例 A,resolve是一个函数,而且不是用户传的,全部Promise自身应该有一个resolve方法,而且这个方法要传递给Promise构造器里面的函数做为参数。函数
function Promise(func){ // 接收一个函数做为参数 **func(this.resolve);** } Promise.prototype = { **resolve: function(){ }**, then: function(callback){ // 接收函数做为参数 return this; // 支持链式调用 } }
Promise是按照顺序来执行callback的,而且由resolve触发。测试
function Promise(func){ // 接收一个函数做为参数 **this.doneList = []; // callback 列表** **func(this.resolve.bind(this)); // 顺带绑定this对象** } Promise.prototype = { resolve: function(){ **//执行回调列表 while(true){ if( this.doneList.length === 0 ){ break; } this.doneList.shift().apply(this); }** }, then: function(callback){ // 接收函数做为参数 **this.doneList.push(callback); // 加入到回调队列** return this; // 支持链式调用 } }
好,如今写一个测试用例this
var p =new Promise(function(resolve){ console.log('a'); resolve(); }).then(function(){ console.log('b'); }); // 输出 'a'
什么鬼?打印下pspa
console.log(p);
咱们发现原来doneList里面还有一个函数没有运行,再运行下这个函数prototype
p.doneList[0].call(this); //结果 console.log('b'); // 打印 b
打断点跟踪,发现Promise先执行resolve方法,而后执行then,把函数push到doneList。可是,再也没有执行过doneList里面的函数了。怎么办呢?咱们能够给Promise加一个属性(state)来描述当前状态,分为【未完成】(pending)和【完成】(done)。若是执行then时,状态已是完成态,那么切换到未完成态,并执行resolve方法。code
function Promise(func){ // 接收一个函数做为参数 **this.state = 'pending'; // 初始化状态** this.doneList = []; // callback 列表 func(this.resolve.bind(this)); // 顺带绑定this对象 } Promise.prototype = { resolve: function(){ //执行回调列表 while(true){ if( this.doneList.length === 0 ){ **this.state = 'done'; // 回调列表为空,改变状态** break; } this.doneList.shift().apply(this); } }, then: function(callback){ // 也是接收函数 this.doneList.push(callback); // 加入到回调队列 if( this.state === 'done'){ this.state = 'pneding'; this.resolve(); } return this; // 支持链式调用 } }
用和上面相似的例子再次测试对象
var p =new Promise(function(resolve){ console.log('a'); resolve(); }).then(function(){ console.log('b'); }).then(function(){ console.log('c'); });
结果截图
这下,咱们自定义的Promise基础功能完成了最核心的部分了。也许有人会疑问,你这写的什么鬼?下面的代码更简单,也能实现相同的功能
function Promise(func){ // 接收一个函数做为参数 func(this.resolve.bind(this)); // 顺带绑定this对象 } Promise.prototype = { resolve: function(){ //什么也不干 }, then: function(callback){ // 也是接收函数 callback.call(this); // 直接运行 return this; // 支持链式调用 } }
测试用例
var p =new Promise(function(resolve){ console.log('d'); resolve(); }).then(function(){ console.log('e'); }).then(function(){ console.log('f'); });
结果:
可是,文章最前面说过
Promise 对象用于延迟(deferred) 计算和异步(asynchronous ) 计算
而且会顺序执行回调列表(doneList)。最终代码及测试
function Promise(func){ this.state = 'pending'; this.doneList = []; func(this.resolve.bind(this)); } Promise.prototype = { resolve: function(){ while(true){ if( this.doneList.length === 0 ){ this.state = 'done'; break; } this.doneList.shift().apply(this); } }, then: function(callback){ this.doneList.push(callback); if( this.state === 'done'){ this.state = 'pending'; this.resolve(); } return this; } } var p = new Promise(function(resolve){ window.setTimeout(function(){ console.log('d'); resolve(); }, 1000); }).then(function(){ console.log('e'); }).then(function(){ console.log('f'); }); console.log('被阻塞了吗?');
输出:
先输出'被阻塞了吗?',一秒钟后相继输出 d、e、f 。能够看出,不但没有阻塞后面的代码执行,并且回调也是按照顺序执行的。
结束。
下篇继续完善,例如数据传递以及then中函数返回一个Promise时,如何处理。欢迎你们有疑问或者建议,一块儿来交流。