Promise应用场景

众所周知,Promise是为了解决回调地狱问题而产生的,其主要应用于向发服务端发起请求等异步操。那么,除了异步请求还有其余场景适合使用 Promise 吗?下面咱们来共同探讨下。javascript

并发执行的任务

Promise除了用于异步操做,还能够用来记录一个业务流程的状态变化,俗称“状态机”。咱们可使用 Promise 提供的 Promise.all 方法来实现并行执行任务。好比如今有一个表单页,里面有若干多个表单项,只有在全部表单都经过校验才容许用户进行下一步操做。下面咱们来提炼关键要素:java

  • 校验表单是并发操做(这里不考虑关联表单)
  • 只有全部表单都校验经过才容许下一步操做

当看到这样的业务逻辑时,是否是首先想到的是设置一个 flag 变量,而后经过改变flag变量来表示全部表单是否校验经过,这是最容易想到的实现思路。promise

let flag = true;
let fields = [];

fields.forEach(field=>{
    if(!field.validate()) {
  	    flag = false;//校验不经过
    }
})
复制代码

咱们如今来考虑下这么作有没有问题?咱们保存了多余的变量,而且这样的代码是不支持远程服务端校验的,若是要支持异步操做须要增长更多的代码量,并且这样的代码也是难以理解和维护的。这个时候咱们不妨转换下思路,将每一个表单项校验看作是一个 Promise 状态机,当校验经过, Promise 状态为 fullfilled,校验不经过为 rejected。如今咱们使用 Promise 重构上面的代码,使每个表单校验都支持异步操做,而且更加容易理解。并发

咱们能够利用 Promise.all的特性,只有在全部表单项状态都为fullfilled状况下,才容许执行Promise.all后面的then方法app

let p1 = new Promise(function(resolve,rejected) {
	//表单1校验经过
  if(field.validate()) {
  	resolve()
  } else {
  	rejected()
  }
})
//p2,p3...
Promise.all([p1,p2,p3...]).then(()=>{
	//全部表单项都校验经过
})
复制代码

顺序执行的任务

有时候咱们会遇到有一系列任务顺序执行的状况。举个例子,如今有一个购物车的需求,用户必须先下单以后才能进行付款,而后付款以后才能够跳转到订单页面,这个需求就能够用 Promise 顺序执行的逻辑实现,状态流转是这样的:异步

咱们来提炼下关键需求点:

  • 每个业务环节须要顺序执行,执行顺序不可变,状态不可逆
  • 上一个执行结果可能须要做为下一步的输入

实现这样的业务逻辑咱们一样能够不使用 Promise,可是可能实现过程较复杂。咱们知道,系统越是复杂,出错的几率越高,因此咱们必须用尽可能简单的方法实现以上需求。这里咱们将用到 Promise 的顺序执行。
实现Promise顺序执行需求如下两个步骤:async

  • 定义一个空的 resolved promise,这个promise只是做为创建链的起点
  • 在一个循环中,经过链中上一个 promise 调用 then()得到新的 promise,更新promise 变量
//利用forEach实现
function run(tasks=[]) {
  let promise = Promise.resolve();
  tasks.forEach(task=>{
    promise = promise.then((value)=>{
      return task(value);
    })
  })
  return promise;
}
复制代码

//利于reduce实现
function run(tasks=[]) {
  let promise = tasks.reduce((prev,task)=>{
    return prev.then((value)=>{
      return task(value);
    })
  },Promise.resolve());
	return promise
}
复制代码

兼容callback模式

固然,Promise并非万金油,不是全部的场合都适合用 Promise。若是是较为简单的逻辑,使用 callback 会更加方便。并且若是咱们是在写一个不少人都在用的公共库的话,有些开发者可能不喜欢使用Promise或者对 Promise 不熟悉。这时,咱们须要提供一种解决方案,使咱们的API能够同时兼容 Promise 和 callback 两种模式。提供一个回调API,回调参数可选,通常状况下使用 callback,在 callback 未传递的状况下使用 Promise。咱们能够经过高阶函数实现此功能:函数

//将返回promise的函数转化为既返回promise又支持
//callback的函数,调用时最后一个参数为callback
function ptc (fn) {
	if(typeof fn !== 'function') {
		throw new Error("缺乏必要参数");
	}
	return function(...args) {
		let callback = args[args.length-1];
		let _args = args.slice(0,args.length-1);
		return fn.apply(this,args).then(res=>{
			if(typeof callback == 'function') {
				callback.call(this,null,res)
			}
			return res;
		}).catch(e=>{
			if(typeof callback == 'function') {
				callback.call(this,e,null)
			}
			return e;
		})
	}
}

//测试
a= function(x) {return Promise.resolve(x)}

b=pc(a)

b('xxx',function(err,data){
    console.log(err,data)//err:null,data:'xxx'
})


b('asss').then(res=>{
	console.log(res);
})

复制代码

总结

Promise 实例能够看作是一个状态机,任何具备状态和状态改变的业务流程均可以使用 Promise 来实现,在结合了 ES7 的 async function特性后功能更增强大。这里咱们只是列举了两个很简单的小例子来帮助你们理解,更多复杂的应用场景等待你们去细心观察和总结,共勉!测试

相关文章
相关标签/搜索