Source code reading: promiseify

Source code reading: promiseify

Introduction

In JavaScript, callback functions are a common way of handling asynchronous operations. However, using callback functions can lead to code that is too deeply nested to understand and maintain. PromiseifySolving this problem, it can convert callback-based asynchronous functions into returned Promisefunctions, making it easier for developers to handle asynchronous operations and Promisewrite code using chain calls, using clearer and more concise code to handle asynchronous operations.

PromiseifyThe use is very simple, just call its function and pass in the asynchronous function that needs to be converted as a parameter. PromiseifyWill return a new function, this new function returns an Promiseobject. We can perform original asynchronous operations by calling this returned function and Promisehandle results and errors using chained calls.

promiseifyThe basic usage is as follows:

  1. Import promiseifythe module (CommonJS as an example):
const promiseify = require('promiseify');
  1. Pass the function that needs to be converted into promiseifythe function and get the returned Promiseversion of the function:
const promiseFunc = promiseify(callbackFunc);
  1. Use the returned promiseFuncfunction for asynchronous operations:
promiseFunc(args)
  .then((result) => {
    
    
    // 处理成功的结果
  })
  .catch((error) => {
    
    
    // 处理错误
  });

promiseifyThe working principle is by wrapping the original callback function in a new one Promiseand determining Promisethe state based on the execution result of the callback function. If the callback function executes successfully, Promiseit will be parsed as a success status and the result value will be passed; if the callback function fails, Promiseit will be rejected and an error object will be passed.

Source code interpretation

'use strict';

First, the code uses strict mode ( 'use strict') to ensure the rigor and security of the code.

Next, a function is defined promiseifythat accepts two parameters: methodand ctx(optional). methodThe parameter is the function that needs to be converted, and ctxthe parameter is the context ( ) that serves as the function this.

/**
 * promiseify
 * @param {function} method function
 * @param {object} ctx optional ctx for method
 */
function promiseify(method, ctx) {
    
    

  // check first
  if (typeof method !== 'function') {
    
    
    throw new TypeError(String(method) + ' is not a function');
  }

  return function() {
    
    

    // runtime args
    var args = [].slice.call(arguments);

    // runtime this
    ctx = ctx || this;

    return new Promise(function(resolve, reject) {
    
    

      args.push(function(err) {
    
    
        if (err) {
    
    
          return reject(err);
        }
        var arg = [].slice.call(arguments);
        if (arg.length === 2) {
    
    
          resolve.call(this, arg[1]);
        } else {
    
    
          resolve.call(this, arg.slice(1));
        }
      });

      try {
    
    
        method.apply(ctx, args);
      } catch (err) {
    
    
        reject(err);
      }
    });
  };
}
  1. The code first performs a parameter check to ensure that the method parameter is a function. If it is not a function, a type error is thrown.
  2. Then, a new function is returned, which becomes the returned Promiseversion of the function.
  3. Inside the new function, first get the runtime parameters ( arguments) and convert them into an array.
  4. thisNext, set the execution context of the function based on the passed in context parameter or the default context ( ).
  5. Then, create a new one Promiseand Promisepass in a new callback function as a parameter in the constructor. This callback function accepts two parameters: resolveand reject.
  6. In the callback function, first check whether there is an error parameter ( err). If there is an error, rejectthe method will Promisebe rejected and the error object will be passed.
  7. If there are no errors, use [].slice.call(arguments)Convert the callback function parameters to an array ( arg).
  8. resolveNext, the parameters passed when calling are determined based on the length of the parameters . If the parameter length is 2, it means there is an error parameter and a result parameter. At this time, resolvethe method is called and the result parameter ( arg[1]) is passed; otherwise, resolvethe method is called and the array of result parameters ( arg.slice(1)) is passed.
  9. Finally, try-catchthe original async function ( method.apply(ctx, args)) is executed in the block, and if an error occurs, the consuming rejectmethod will Promisereject, passing the error object.
/**
 * promiseify all
 * @param  {object} o the target object
 * @return {object}   same to target object
 *
 * @example
 *   var fs = promiseify.all(require('fs'));
 *   fs.readFileAsync('file.txt', 'utf8')
 *     .then(function(s){ console.log(s); });
 *
 *   var Connection = require('mysql/lib/Connection');
 *   promiseify.all(Connection.prototype);
 *   // conn.connectAsync / conn.queryAsync / conn.endAsync available now
 */
promiseify.all = function(o) {
    
    
  Object.keys(o)
    .filter(function(m) {
    
    
      return typeof o[m] === 'function';
    })
    .forEach(function(m) {
    
    
      o[m + 'Async'] = promiseify(o[m]);
    });
  return o;
};

This part is a promiseify.allfunction that takes an object as a parameter and iterates through all the properties of that object. For attributes whose value is a function, convert it to Promisea version of the function and add the new function to the object with the original function name plus Asynca suffix.

Object.defineProperty(promiseify, "__esModule", {
    
     value: true });
promiseify.default = promiseify;
module.exports = promiseify;

This code is mainly used to export promiseifythe function as a module. First, use Object.definePropertythe method to promiseifyadd a "__esModule"property named to the object with a value of true. This is to indicate that the module is an ES module. Next, set promiseify.defaultthe property to promiseifythe function itself. In this way, when using importsyntax import, you can get promiseifythe function directly. Finally, use module.exportsexport promiseifythe function as a module. requireIn this way, the function can be obtained when using the syntax import promiseify.

expand

In JavaScript, an array-like object refers to an object that has the characteristics of an array, but is not a true array. They have an array-like length property and the ability to access elements by index. However, array-like objects do not have the prototype methods and properties of arrays.

Common array-like objects include:

  1. argumentsObject: An object automatically created inside a function to store parameters passed to the function.
  2. DOM element list (NodeList): A collection of objects returned by querying DOM elements, such as querySelectorAllresults obtained through methods.
  3. String: Characters in a string can be accessed by index.
  4. Array-like objects: Some objects may be designed to resemble arrays, for example by implementing an array-like iterator interface.

There are several ways to convert an array-like object into a real array:

  1. Usage Array.from(): Array.from()Method can convert an array-like object or iterable object into a new array. For example:var array = Array.from(arrayLike);
  2. Use the spread operator (Spread Operator): The spread operator (...) can spread an array-like object into a new array. For example:var array = [...arrayLike];
  3. Usage : You can convert an array-like object to an array Array.prototype.slice.call()by calling the method and passing in an array-like object as its context. Array.prototype.sliceFor example:var array = Array.prototype.slice.call(arrayLike);
  4. Usage Array.prototype.concat(): You can convert an array-like object to an array by calling Array.prototype.concatthe method and passing in an array-like object as a parameter. For example:var array = Array.prototype.concat.call([], arrayLike);

It should be noted that the above methods all create a new array rather than directly modifying the original array-like object.

Guess you like

Origin blog.csdn.net/p1967914901/article/details/132024074