[Lectura del código fuente] Edición 4 | código fuente co

1. Introducción

2. Conocimientos básicos

co se usa para convertir la función Generador en una Promesa y ejecutarla, de modo que pueda async、awaitejecutarse automáticamente como una función.

2.1 Generador

Generador pasando parámetros

2.2 Casos de uso del generador

Consulte el análisis del código fuente en el artículo de Ruochuan y escriba uno por imitación.

  1. Ejecución del generador
// 模拟请求
function request(ms = 1000) {
        return new Promise(resolve => {
                setTimeout(() => {
                        resolve(111)
                }, ms)
        })
}
// 生成器函数
function* generatorFunc() {
        const res = yield request()
        console.log('打印***res', res)
}

generatorFunc()

imagen.png

Obtendrá one 迭代器对象, y obtendrá el resultado solo llamando al siguiente método, y no obtendrá el resultado si no lo ejecuta. Entonces, ¿puede escribir una herramienta de ejecución automática para completar esta función?

  1. Primera versión - ejecución automática de rendimiento único
function request(ms = 1000) {
        return new Promise(resolve => {
                setTimeout(() => {
                        resolve(111)
                }, ms)
        })
}

function* generatorFunc() {
        const res = yield request()
        console.log('打印***res', res)
}

function coSimple(gen) {
        gen = gen()
        console.log('打印***gen', gen)

        const ret = gen.next()
        const promise = ret.value

        promise.then(res => {
                gen.next(res)
        })
}

coSimple(generatorFunc)

Use next para llamar, envuelva el resultado en una promesa y use gen.next(res) para devolver el resultado de la ejecución.Si no se llama a next, el res después del rendimiento de la función del generador no está definido.

imagen.png

  1. Segunda versión: considere rendimientos múltiples y paso de parámetros

function* generatorFunc2(suffix=''){
        const res = yield request()
        console.log('打印***res-1'+suffix,res)

        const res2 = yield request()
        console.log('打印***res-2'+suffix,res2)
}

function coSimple2(gen){
        const ctx = this
        const args = Array.prototype.slice.call(arguments,1)// 转成数组
        gen = gen.apply(ctx,args)
        console.log('打印***gen',gen)

// 第一个调用
        const ret = gen.next()
        console.log('打印***ret',ret)

        const promise = ret.value
        promise.then(res=>{
                console.log('打印***res',res)
                const ret = gen.next(res)// 此处不传入,则yield后面读取不到res,111
                const promise = ret.value
                promise.then(res=>{
                        gen.next(res)
                })
        })
}

coSimple2(generatorFunc2,'888')

Aquí, se anidan varias llamadas de rendimiento y el valor se obtiene manualmente cada vez. Entonces puede ser automático y manual, hasta el final.

imagen.png

  1. Versión 3 - Rendimiento ilimitado
let index = 0
function request(ms = 1000) {
        return new Promise(resolve => {
                setTimeout(() => {
                        resolve(index++)
                }, ms)
        })
}


function* generatorFunc3(suffix=''){
        const res = yield request()
        console.log('打印***res-1'+suffix,res)

        const res2 = yield request()
        console.log('打印***res-2'+suffix,res2)

        const res3 = yield request()
        console.log('打印***res-3'+suffix,res3)

        const res4 = yield request()
        console.log('打印***res-4'+suffix,res4)
}

function coSimple3(gen){
        const ctx = this
        const args = Array.prototype.slice.call(arguments,1)
        gen = gen.apply(ctx,args)

        console.log('打印***gen',gen)

        return new Promise(()=>{
                function onFulfilled(res){
                        const ret = gen.next(res)
                        console.log('打印***ret',ret)
                        next(ret)
                }

                function next(ret){
                        const promise = ret.value
                        promise&&promise.then(onFulfilled)
                }
                onFulfilled()
        })
}

coSimple3(generatorFunc3)


Se modificó la solicitud para que sea más fácil ver el paso de cada parámetro.

Devuelva la promesa, defina onFulfilled, llame manualmente a next para ejecutar la solicitud, use next para obtener el último resultado y se llame a sí mismo hasta que se ejecuten todos los rendimientos.

imagen.png

3. Análisis del código fuente

3.1 Método de función

  1. slice: se utiliza para crear una Array.prototype.slicereferencia a un archivo .
  2. co: Función principal, convertir la función Generador o el objeto Generador en Promesa y ejecutar.
  3. co.wrap: Envuelve la función de Generador dada en una función que devuelve una Promesa.
  4. toPromise: yieldConvierte el valor en una Promesa.
  5. thunkToPromise: Convierte un thunk (una función que acepta una devolución de llamada) en una Promesa.
  6. arrayToPromise: Convierte una matriz que contiene múltiples "rendibles" en una Promesa.
  7. objectToPromise: Convierte un objeto que contiene múltiples "rendibles" en una Promesa.
  8. isPromise: Comprueba si un objeto es una Promesa.
  9. isGenerator: Comprueba si un objeto es un Generador (tiene nexty throwmétodos).
  10. isGeneratorFunction: comprueba si una función es una función de generador.
  11. isObject: Comprueba si un valor es un objeto simple.

3.2 co función

function co(gen) {
  var ctx = this; // 保存当前上下文
  var args = slice.call(arguments, 1); // 获取除了第一个参数(gen)之外的其他参数

  // 我们将所有内容包装在一个 Promise 中,以避免 Promise 链式调用导致的错误。
  return new Promise(function(resolve, reject) {
    if (typeof gen === 'function') gen = gen.apply(ctx, args); // 如果 gen 是函数,则执行函数并将结果赋值给 gen
    if (!gen || typeof gen.next !== 'function') return resolve(gen); // 如果 gen 不是函数,或者不具有 next 方法,则直接返回结果为 gen 的 Promise

    onFulfilled();

    // 当前步骤执行成功时的处理函数
    function onFulfilled(res) {
      var ret;
      try {
        ret = gen.next(res); // 执行生成器的 next 方法,并将结果赋值给 ret
      } catch (e) {
        return reject(e); // 如果出现异常则将异常作为 Promise 的拒绝理由
      }
      next(ret); // 继续执行下一步
      return null;
    }

    // 当前步骤执行失败时的处理函数
    function onRejected(err) {
      var ret;
      try {
        ret = gen.throw(err); // 执行生成器的 throw 方法,并将结果赋值给 ret
      } catch (e) {
        return reject(e); // 如果出现异常则将异常作为 Promise 的拒绝理由
      }
      next(ret); // 继续执行下一步
    }

    // 获取生成器的下一个值,并返回一个 Promise
    function next(ret) {
      if (ret.done) return resolve(ret.value); // 如果生成器完成,则将生成器的结果作为 Promise 的解决值
      var value = toPromise.call(ctx, ret.value); // 将生成器的返回值转换为 Promise
      if (value && isPromise(value)) return value.then(onFulfilled, onRejected); // 如果返回值是 Promise,则等待 Promise 的状态并执行相应的处理函数
      return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
        + 'but the following object was passed: "' + String(ret.value) + '"')); // 如果生成器的返回值不是函数、Promise、Generator、数组或对象,则拒绝 Promise
    }
  });
}



En cola función, primero juzgará si el parámetro entrante genes una función de Generador y, de ser así, ejecutará la función para obtener el objeto Generador. Luego, ejecute el método del objeto Generador en una nueva Promesa nexty realice el procesamiento correspondiente de acuerdo con el resultado devuelto hasta que se complete el Generador ( doneverdadero), y finalmente devuelva el resultado de la Promesa.

4. Resumen

Al estudiar coel código fuente, aprendí:

  1. yieldCómo escribir código asíncrono usando funciones de generador y la palabra clave.
  2. next()Cómo usar los métodos y de las funciones del generador throw()para controlar el flujo de ejecución de los generadores.
  3. Cómo manejar el valor de retorno de una operación asincrónica. coLa función pasa el valor de retorno de la operación asincrónica como argumento a la yieldexpresión de la función generadora y suspende el flujo de ejecución de la función generadora hasta la siguiente llamada al next()método.

Aprender juntos y crecer juntos. O ^ O


Ejecución automática de Generador en serie ES6

Aprenda la estructura general del código fuente de koa y analice el principio del modelo de cebolla de koa y el principio co

Supongo que te gusta

Origin juejin.im/post/7259681568414416951
Recomendado
Clasificación