Promise,我们来实战
Promise的基础我就不说了,我更加关心的是Promise能带给我什么便利?这也是本文的内容所在。
Promise.all
并发执行多个异步方法,统一返回结果,结果按照参数的顺序返回。
const getRandom = () => +(Math.random()*1000).toFixed(0); const asyncTask = taskID => new Promise(resolve => { let timeout = getRandom(); console.log(`taskID=${taskID} start.`); setTimeout(function() { console.log(`taskID=${taskID} finished in time=${timeout}.`); resolve(taskID) }, timeout); }); Promise.all([asyncTask(1),asyncTask(2),asyncTask(3)]) .then(resultList => { console.log('results:',resultList); });
上面的这个方法能够很好的看出Promise.all的执行方式,Promise.all的作用是显而易见的,比如我的页面上有多个请求,但是这些请求并没有任何联系,但是整个页面需要等这几个请求数据都获取到之后我们才能正确的展示页面,在之前一段时间里,我们可能会使用嵌套的方式去逐个请求,但考虑到这样会浪费时间,我们可能会优化自己的写法,通过计时器的方式去处理。其实计时器的原理跟Promise.all的实现的结果就差不多,而有了Promise.all之后就可以直接把几个异步的请求方法作为参数直接调用Promise.all了,so easy不是吗?
Promise.race
并发执行多个异步方法,返回最快的执行结果。
const getRandom = () => +(Math.random()*1000).toFixed(0); const asyncTask = taskID => new Promise(resolve => { let timeout = getRandom(); console.log(`taskID=${taskID} start.`); setTimeout(function() { console.log(`taskID=${taskID} finished in time=${timeout}.`); resolve(taskID) }, timeout); }); Promise.race([asyncTask(1),asyncTask(2),asyncTask(3)]) .then(resultList => { console.log('results:',resultList); });
同样的这个例子也能很好的说明race的作用,race的作用,为了保障能够获取到数据,我们通过多个不同的方法去获取数据,但其实这几个方法返回的数据是相同的,只要任何一个方法成功返回了,我们就可以获取到自己想要的数据了。
看了上面两个例子之后是不是对Promise的作用更加了解了,其实前端业务开发中只要有了多个异步方法就可以使用Promise了,这也是目前最优雅的编码方式。尽量去用就对了,没毛病。
上面两种方法是Promise自带的,但是实际情况中有很多情况下,多个请求之间是有依赖关系的,所以我新增waterfall方法
Promise.waterfall
多个函数依次执行,且前一个的输出为后一个的输入。
实现如下面:
Promise.waterfall = function(promises){ if (!Array.isArray(promises)) { throw new TypeError('You must pass an array to all.'); } // 返回一个promise 实例 return new Promise(function(resolve, reject){ var i = 0, result = [], len = promises.length, count = len; // 每一个 promise 执行成功后,就会调用一次 resolve 函数 function resolver(index) { return function(value) { resolveWaterfall(index, value); }; } function rejecter(reason){ reject(reason); } function resolveWaterfall(index, value) { if( index == len){ resolve(value) } else { promises[index](value).then(resolver(index + 1), rejecter); } } resolveWaterfall(0); }); };
同样的我们通过一段测试代码来看其执行结果
const getRandom = () => +(Math.random()*1000).toFixed(0); const asyncTask = taskID => new Promise(resolve => { taskID = taskID || 1; let timeout = getRandom(); console.log(`taskID=${taskID} start.`); setTimeout(function() { console.log(`taskID=${taskID} finished in time=${timeout}.`); resolve(taskID + 1) }, timeout); }); Promise.waterfall([asyncTask, asyncTask, asyncTask]).then(value => console.log(value))
返回的结果是4,三个异步方法依次执行,并且把前一次的输出作为下一次的输入执行。
Promise.waterfall = function(promises){ if (!Array.isArray(promises)) { throw new TypeError(‘You must pass an array to all.’); } // 返回一个promise 实例 return new Promise(function(resolve, reject){ var i = 0, result = [], len = promises.length, count = len;
// 每一个 promise 执行成功后,就会调用一次 resolve 函数 function resolver(index) { return function(value) { resolveWaterfall(index, value); }; }
function rejecter(reason){ reject(reason); }
function resolveWaterfall(index, value) { if( index == len){ resolve(value) } else { promises[index](value).then(resolver(index + 1), rejecter); } }
resolveWaterfall(0); });};