等待者模式

等待者模式用于处理多个异步逻辑的顺序,Promise.all是其常见应用。本文介绍了等待者模式的概念、代码实现、使用方式,特别是轮询机制在ajax中的设计。同时,文章还探讨了Promise.all的工作原理,并提供了源码链接。作者是一名前端开发者,热衷于分享技术和生活心得,文章中包含了个人站点和社交媒体联系方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概念

等待者模式或者等待者对象指的是多个异步逻辑无法确认先后执行的顺序以及时机时,而我们增加对异步逻辑的监听,当每个异步状态发生变化时,进行一次确认状态,然后根据结果来决定是否执行某动作。

我们常见常用的Promise.all对象就是等待者模式的一种最佳实践。

本文codepen地址:https://codepen.io/robinson90/pen/YzPQaoe

代码实现

let Waiter = function(){
  // 定义内部的监听对象数组,成功回调数组,失败回调数组
	let dfd = [],doneArr = [], failArr= [],
      slice = Array.prototype.slice,that = this;
  let Primise = function(){
  	this.resolved = false 
    this.rejected = false
  }
  Primise.prototype = {
    resolve:function(){
      // 设置当前对象解决
      this.resolved = true
      //如果没有监听对象 直接返回
      if(!dfd.length){
      	return
      }
      for(let i = dfd.length -1 ;i>=0;i--){
        // 判断监听对象中是否有未解决或者解决失败的 如果有直接返回 不执行
        if(dfd[i] && !dfd[i].resolved || dfd[i].rejected){
        		return 
        }
        // 删除监听对象
        dfd.splice(i,1)
      }
      // 都执行完成,那么执行回调函数的数组
      _exec(doneArr)
    },
    reject:function(){
      // mark fail
      this.rejected = true
      // no dfd,return
      if(!dfd.length){return}
			// eclear all dfd
      dfd.splice(0)
      //执行失败回调函数
      _exec(failArr)
    
    }
  }
  that.Deferred = function(){
  	return new Primise()
  }
  // 执行回调函数数组
  function _exec(arr){
    let len = arr.length
  	for(let i =0;i<len;i  ){
    	try{
      	let fn = arr[i]
        if(fn && typeof fn === 'function'){
        	fn()
        }
      }catch(e){
      }
    }
  }
  /**
  * @description 监控异步方法 参数为监听对象 
  */
  that.when = function(){
  	dfd = slice.call(arguments)
    let i = dfd.length
    for(;i>=0;i--){
      // 当不存在 或者 已经完成或者失败 或者 不为primise的实例,直接清除监控
    	if(!dfd[i] || dfd[i].resolved || dfd[i].rejected || !dfd[i] instanceof Primise) {
      	dfd.splice(i,1)
      } 
    }
    return that
  }
  // 成功的回调函数添加方法
  that.done = function(){
    doneArr = doneArr.concat(slice.call(arguments))
    return that
  }
  
  //失败的回调函数添加方法
  
  that.fail = function(){
    failArr = failArr.concat(slice.call(arguments))
    return that
  }      
  
}

使用方式

const waiter = new Waiter()
//fn1 fn2 为两个异步执行的方法
const first = function(){
  let dfd = waiter.Deferred()
  setTimeout(()=>{
  console.log('first finish')
    dfd.resolve()
  },1000)
  return dfd
}()

const second = function(){
  let dfd = waiter.Deferred()
  setTimeout(()=>{
  console.log('second finish')
    dfd.resolve()
  },1000)
  return dfd
}()
Waiter.when(first,second).done(()=>{
}).fail(()=>{
})

轮询机制的设计

const search = function(){
  window.counter =Math.random(1)
  console.log('查询一次')
}

const longSearch = (fn,time)=>{
  let timer = setInterval(()=>{
    if(window.counter>0.8){
      console.log('查询结束',window.counter)
      clearInterval(timer)
      return 
    }
    fn()
  },time)
  
}

longSearch(search,500)

ajax的轮询设计

封装一个deferred对象,然后在xhr的结果返回之后使用其回调函数。

$.ajax = function(url,success,fail){
		const xhr = new XMLHttpRequest()
    let dfd = waiter.Deferred();
  	xhr.onload = function(event){
    	if(xhr.status>=200){
        success && success()
      	dfd.resolve()
      }else {
      	dfd.reject()
        fail && fail()
      }
    }
} 

promise.all

基本思路:本身也是一个异步方法,维护所有异步方法的程度 遗留长度,维护一个结果数组,每执行一个,标记一个结果,根据策略决定,是完成全部结束还是完成一个结束,然后fullfill标记完成

promise.all 源码地址:https://github.com/stefanpenner/es6-promise/blob/master/lib/es6-promise/enumerator.js

小结

看完等待者模式,是不是觉得这个模式其实很常用,设计的很巧妙,在没有promise这个模型的时候,其实就已经出现类似的技术方案,不同的只是没有定制为一个技术规范。

关于我

我是一名前端Coder,热爱分享生活与技术中的经验与心得。
我是一名旅游爱好者,爱好拍摄旅途中的风景与人物。
我是一名写作狂人,基本每天都有新文章产出,笔耕不辍。

个人站点

  • GitHub:http://github.com/robinson90
  • codepen:https://codepen.io/robinson90
  • personal blog: http://damobing.com
  • yuque docs: https://www.yuque.com/robinson
  • juejin blog: https://juejin.im/user/5a30ce0c51882561a20a768b

个人微信号与公众号

微信:csnikey,或者扫码加我
微信号图片

达摩空间订阅号:damo_kongjian,或者扫描下面的二维码

微信号图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值