网站搜索

javascript - 传递和调用函数的正确方法


在 Node 中使用外部 SDK 时,我注意到我写了很多重复的代码。例如:

async function one(): Promise<any> {
  return new Promise((resolve, reject) => {
    sdk.one(function(err, req, res) {
      if (err) {
        return reject(err);
      }

      resolve(res);
    });
  });
}

async function two(): Promise<any> {
  return new Promise((resolve, reject) => {
    sdk.two(function(err, req, res) {
      if (err) {
        console.log(err);
        return reject(err);
      }

      resolve(res);
    });
  });
}

我想简化和抽象它,使其更清晰,然后想到了这个:

async function runner(fn, params?): Promise<any> {
  return new Promise(function(resolve, reject) {
    const _CB = cb.bind({ resolve, reject });
    if (params) {
      return fn(params, _CB);
    }

    return fn(_CB);
  });
}

const one = async (): Promise<any> => {
  return runner(sdk.one);
};

const two = async (): Promise<any> => {
  return runner(sdk.two);
};

不过,当我运行这个时会遇到错误,即 this.helper is not a function。我认为问题在于 Javascript 是按值传递的。因此,当我在 runner 内运行 fn(_CB) 并尝试引用其父级的一个函数 this.helper 时,它不知道 this 是什么,因为 fn 只是一个复制出来的代码块。实际上,在我想到这个之前,我尝试过对 sdk 函数使用 util.Promisify,但仍然出现和这里一样的错误。

我想到了这个变通办法,但我想知道是否有更好的方法?

async function runner(fn, params?): Promise<any> {
  return new Promise(function(resolve, reject) {
    const _CB = cb.bind({ resolve, reject });
    if (params) {
      return fn(params, _CB);
    }

    return fn(_CB);
  });
}

const one = async (): Promise<any> => {
  return runner((x) => sdk.one(x));
};

答案#1

当 SDK 尝试回调你时,你的作用域丢失了吗?你可以使用箭头函数在这些调用中保留作用域。它的工作方式类似于你为较旧目标使用的中间 _CB 变量,但在更新的 ECMAScript 版本中,它是原生支持的。

async function one(): Promise<any> {
  return new Promise((resolve, reject) => {
    sdk.one((err, req, res) => { // Scope preserving arrow function
      if (err) {
        return reject(err);
      }

      resolve(res);
    });
  });
}

async function two(): Promise<any> {
  return new Promise((resolve, reject) => {
    sdk.two((err, req, res) => { // and here
      if (err) {
        console.log(err);
        return reject(err);
      }

      resolve(res);
    });
  });
}

答案#2

嗯,你在使用 JavaScript,这种语言几乎允许你做任何事情。你可以动态调用函数

async function promisify(fnName): Promise<any> {
  return new Promise((resolve, reject) => {
    sdk[fnName](function(err, req, res) {
      if (err) {
        return reject(err);
      }

      resolve(res);
    });
  });
}

并将其称为 promisify('one')

如果你正在使用当前的 LTS 8.X Node 版本或更高版本,你可以使用 https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original

如果不行,你可以尝试使用蓝鸟方法来处理:http://bluebirdjs.com/docs/api/promise.promisify.html