备忘录-promise & koa执行顺序

312 阅读2分钟

问题:执行如下代码打印顺序是什么

function newPromise_resolve() {
   return new Promise((resolve,reject) => {
      resolve(); //这里调resolve方法,则then方法会被调用
      console.log('resolve里面的log');
   })
   
}

newPromise_resolve().then(() => {
   console.log('then方法');
});

打印顺序如下

resolve里面的log
then方法

解析(如果回答对了,可以跳过)

其实也没啥可解析的直接看简单实现的源码吧


class MyPromise {
  constructor (handle) {
    if (!isFunction(handle)) {
      throw new Error('MyPromise must accept a function as a parameter')
    }
    // 添加状态
    this._status = PENDING
    // 添加状态
    this._value = undefined
    // 执行handle
    try {
      handle(this._resolve.bind(this), this._reject.bind(this)) 
    } catch (err) {
      this._reject(err)
    }
  }
  // 添加resovle时执行的函数,此处只是做了两件事1改变状态2记录value
  _resolve (val) {
    if (this._status !== PENDING) return
    this._status = FULFILLED
    this._value = val
  }
  // 添加reject时执行的函数
  _reject (err) { 
    if (this._status !== PENDING) return
    this._status = REJECTED
    this._value = err
  }
  // 
  then (onFulfilled, onRejected) {
    const { _value, _status } = this
    switch (_status) {
      // 当状态为pending时,将then方法回调函数加入执行队列等待执行
      case PENDING:
        this._fulfilledQueues.push(onFulfilled)
        this._rejectedQueues.push(onRejected)
        break
      // 当状态已经改变时,立即执行对应的回调函数
      case FULFILLED:
        onFulfilled(_value)
        break
      case REJECTED:
        onRejected(_value)
        break
    }
  // 返回一个新的Promise对象
  	return new MyPromise((onFulfilledNext, onRejectedNext) => {
  	})
   }
}

类koa事件模型


import request, { extend } from 'umi-request';
request.use(async (ctx, next) => {
  console.log('a1');
  await next();
  console.log('a2');
});
request.use(async (ctx, next) => {
  console.log('b1');
  await next();
  console.log('b2');
});

const data = await request('/api/v1/a');

执行顺序如下:

a1 -> b1 -> response -> b2 -> a2

简单源码实现


// 简化 koa-compose 源码下的 compose 方法
function compose(middleware) {
    return function (context, next) {
        return dispatch(0)
        function dispatch(i) {
            let fn = middleware[i]
            if (i === middleware.length) fn = next
            if (!fn) return Promise.resolve()
            try {
                return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
            } catch (err) {
                return Promise.reject(err)
            }
        }
    }
}


class App {
    constructor() {
        // 定义中间件数组
        this.middleware = [];
    }

    use(fn) {
        if (fn && typeof fn !== "function") throw new Error('入参必须是函数');
        // 入参 fn 都传入到 middleware 中间件数组中
        this.middleware.push(fn);
    }

    listen(...arg) {
        /**
        * 源码,this.callbakck() 作为请求处理函数,本处省略该过程
        * const server = http.createServer(this.callback());
        * return server.listen(...args);
        */
        this.callback();
    }

    callback() {
        const fn = compose(this.middleware);
        return this.handleRequest(fn);
    }

    handleRequest(fnMiddleware) {
        return fnMiddleware()
            .then(() => { console.log('over'); })
            .catch((err) => { console.log(err); });
    }
}

简要描述为 在 调用use的时候把中间件放到middleware数组中

在调用callback时 通过调用compose返回 dispatch外层函数, context会一直保留,每次调用next相当于调用了dispatch(i)函数,每次i都会加1,也就是会调用下一个next函数