js异步编程学习

本文详细介绍了JavaScript中的异步编程方法,包括回调函数、事件监听、发布/订阅模式以及Promise对象的使用。通过示例代码展示了Promise的创建、链式调用以及如何封装Ajax请求。最后,还实现了一个简易的Promise类,解释了其工作原理和状态转换。文章旨在帮助开发者深入理解并熟练掌握JavaScript异步编程。
摘要由CSDN通过智能技术生成

标题

实现JavaScript异步编程方式:回调函数、事件监听、发布/订阅、Promise对象
详细的介绍点击这个链接

回调函数

回调函数是所有异步编程方案的根基。

function foo (callback) {
  setTimeout(function () {
    callback()
  }, 3000)
}

foo(function () {
  console.log('这个就是一个回调函数');
  console.log('调用者定义这个函数,执行者执行这个函数');
  console.log('其实就是调用者告诉执行者异步任务结束后应该做什么');
})
promise
const promise = new Promise(function (resolve, reject) {
  // 这里用于兑现承诺 。这个函数会在构造promise的过程中同步执行。
  // 承诺一旦执行;不管是失败还是达成;都无法再次改变
  // resolve(100) // 承诺达成 可以把pending状态改为fulfilled
  console.log('start');

  reject(new Error('promise rejecced')) // 承诺失败
})

promise.then(function (val) {
  console.log(val, '这个是承诺达成的结果');
}, function (error) {
  console.log(error);
})

console.log('end');


// 执行顺序: start end  error/100

Promise封装Ajax

// Promise 方式的AJAX
function ajax (url) {
  return new Promise(function (resolve, reject) {
    var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
    var xhr = new XMLHttpRequest()
    xhr.open('GET', url)
    // 相应类型为json;html5引入的新特性
    xhr.responseType = 'json'
    // 设置请求头
    xhr.setRequestHeader('app_device', '1');

    // html5中提供的新事件 请求完成过后;也就是传统的readystate==4的状态才会执行
    xhr.onload = function () {
      if (this.status == 200) {
        // 请求成功
        resolve(this.responseText)
      } else {
        reject(new Error(this.statusText))
      }
    }
    // 开始执行这个异步请求(发送http请求)
    xhr.send()
  })
}
url = '这里是需要请求的网址'
ajax(url).then(function (res) {
  console.log(res, '这个是返回结果');

}, function (error) {
  console.log(error);
})
Promise的链式调用
// Promise对象的then方法会返回一个全新的Promise对象
// 后面的then方法就是在为上一个then返回的Promise注册回调
// 前面then方法中回调函数的返回值会作为后面的then方法回调的参数
// 如果回调中返回的是Promise,那后面then方法的回调会等待它的结束。
.catch可以获取全部then里面的异常;不用在每个then里面写reject函数了。

实现Promise

// 1 Promise 就是一个类;需要传递一个参数,参数是一个回调函数(执行器)立即执行。  
/*
  2、Promise中有三个状态 分别为成功 fulfiled、失败 rejected、等待 pending
  一旦状态确定就不可以更改;
  3、resolve和rejected是用来更改状态的
  4、then方法内部做的事情就判断状态;如果状态是成功,调用成功地回调函数 如果状态是失败;就调用失败的回调函数
  5、then成功回调有一个参数表示成功之后的值;then失败回调失败之后会有一个原因
  6、同一个promise对象下面的 then方法是可以被调用多次的。
  7/  then方法是可以被链式调用的,后面then方法的回调函数拿到的值就是上一个then方法的回调函数的返回值
*/
// myPromsie类
const PENDING = 'pending'  // 状态是等待
const FULFILED = 'fulfiled'   // 成功
const REGECTED = 'rejected'  // 失败
class MyPromise {
  // 构造函数
  constructor (executor) {
    // 捕获执行器错误
    try {
      // executor叫做执行器 ;也就是promise对象中的回调函数;立即执行
      executor(this.resolve, this.reject)
    } catch (e) { this.reject(e) }
  }
  // 类的实例属性
  // promise状态
  status = PENDING;
  // 成功之后的值
  value = undefined;
  // 失败之后的值
  reason = undefined;
  // 成功回调
  successCallback = [];
  // 失败回调
  filCallback = [];


  resolve = (value) => {
    // 如果状态不是pending 就不用管了
    if (this.status !== PENDING) return
    // 将状态改为成功
    this.status = FULFILED
    // 保存成功之后的值
    this.value = value
    // 判断成功回调是否存在;存在就调用  只适用于同步then来调用
    // this.successCallback && this.successCallback(this.value)
    // 异步调用的时候(就是有定时器之类的;然后同事调用多次promise)
    while (this.successCallback.length) this.successCallback.shift()()
  }
  reject = (reason) => {
    if (this.status !== PENDING) return
    this.status = REGECTED
    // 保存失败之后的值
    this.reason = reason
    // 判断失败回调是否存在;存在就调用
    // this.filCallback && this.filCallback(this.reason)
    while (this.filCallback.length) this.filCallback.shift()()

  }
  then (successCallback, filCallback) {

    // 可以实现当then里面不传递回调函数;就会把参数传递给下一个then
    successCallback = successCallback ? successCallback : value => value
    filCallback = filCallback ? filCallback : reason => { throw reason }
    let promise2 = new MyPromise((resolve, reject) => {
      // 判断状态
      if (this.status === FULFILED) {
        // 把下面的代码变为异步代码;就能够使用promise2
        setTimeout(() => {
          try {
            let x = successCallback(this.value)
            // 判断x是普通值还是promise对象
            // 如果是普通值;直接调用resolve
            // 如果是promise对象 查看promise返回的结果
            // 再根据promise对象返回的结果 决定调用resolve还是调用reject
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        }, 0)
      } else if (this.status === REGECTED) {

        setTimeout(() => {
          try {
            let x = filCallback(this.reason)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        }, 0)
      } else {
        // 处于等待
        // 把成功后的回调和失败的回调存储起来
        this.successCallback.push(() => {

          setTimeout(() => {
            try {
              let x = successCallback(this.value)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        });
        this.filCallback.push(() => {
          setTimeout(() => {
            try {
              let x = filCallback(this.reason)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        });
      }
    });

    return promise2
  }
  finally (callback) {
    // 获取当前promise的状态
    return this.then((value) => {
      // 不管是普通值还是promise对象;我们都把它转成promise对象;这样就可以等待异步promise对象的完成。
      return MyPromise.resolve(callback()).then(() => value)
    }, (reason) => {
      return MyPromise.resolve(callback()).then(() => { throw reason })
    })
  }
  catch (failCallback) {
    return this.then(undefined, failCallback)
  }

  static all (array) {
    let result = []
    let index = 0

    return new MyPromise((resolve, reject) => {
      function addData (key, value) {
        result[key] = value
        index++;
        // 通过判断长度;可以等待异步操作的结果都完成之后在调用resolve成功回调
        if (index === array.length) {
          resolve(result)
        }
      }
      // for循环是一瞬间完成的;但是在执行的时候有异步操作;要等待所有的异步完成之后才能调用resolve
      for (let i = 0; i < array.length; i++) {
        let current = array[i]
        // 判断当前参数是否是myPromise的实例对象
        if (current instanceof MyPromise) {
          // promise对象
          current.then((val) => addData(i, val), reason => reject(reason))

        } else {
          // 普通值
          addData(i, array[i])
        }
      }

    })
  }

  // resolve方法实现
  static resolve (value) {
    if (value instanceof MyPromise) return value
    return new Promise(resolve => {
      resolve(value)
    })
  }



}

function resolvePromise (promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }

  // 如何判断是否是promise对象;就看x是不是myPromise 对象的实例
  if (x instanceof MyPromise) {
    // promise对象
    // 需要查看当前promise的状态
    // x.then((value) => resolve(value), (reason) => reject(reason))
    x.then(resolve, reject)
  } else {
    // 普通值
    resolve(x)
  }
}```
// 导出这个类
module.exports = MyPromise

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值