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. Promiseify
Solving this problem, it can convert callback-based asynchronous functions into returned Promise
functions, making it easier for developers to handle asynchronous operations and Promise
write code using chain calls, using clearer and more concise code to handle asynchronous operations.
Promiseify
The use is very simple, just call its function and pass in the asynchronous function that needs to be converted as a parameter. Promiseify
Will return a new function, this new function returns an Promise
object. We can perform original asynchronous operations by calling this returned function and Promise
handle results and errors using chained calls.
promiseify
The basic usage is as follows:
- Import
promiseify
the module (CommonJS as an example):
const promiseify = require('promiseify');
- Pass the function that needs to be converted into
promiseify
the function and get the returnedPromise
version of the function:
const promiseFunc = promiseify(callbackFunc);
- Use the returned
promiseFunc
function for asynchronous operations:
promiseFunc(args)
.then((result) => {
// 处理成功的结果
})
.catch((error) => {
// 处理错误
});
promiseify
The working principle is by wrapping the original callback function in a new one Promise
and determining Promise
the state based on the execution result of the callback function. If the callback function executes successfully, Promise
it will be parsed as a success status and the result value will be passed; if the callback function fails, Promise
it 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 promiseify
that accepts two parameters: method
and ctx
(optional). method
The parameter is the function that needs to be converted, and ctx
the 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);
}
});
};
}
- 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.
- Then, a new function is returned, which becomes the returned
Promise
version of the function. - Inside the new function, first get the runtime parameters (
arguments
) and convert them into an array. this
Next, set the execution context of the function based on the passed in context parameter or the default context ( ).- Then, create a new one
Promise
andPromise
pass in a new callback function as a parameter in the constructor. This callback function accepts two parameters:resolve
andreject
. - In the callback function, first check whether there is an error parameter (
err
). If there is an error,reject
the method willPromise
be rejected and the error object will be passed. - If there are no errors, use
[].slice.call(arguments)
Convert the callback function parameters to an array (arg
). resolve
Next, the parameters passed when calling are determined based on the length of the parameters . If the parameter length is2
, it means there is an error parameter and a result parameter. At this time,resolve
the method is called and the result parameter (arg[1]
) is passed; otherwise,resolve
the method is called and the array of result parameters (arg.slice(1)
) is passed.- Finally,
try-catch
the original async function (method.apply(ctx, args)
) is executed in the block, and if an error occurs, the consumingreject
method willPromise
reject, 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.all
function 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 Promise
a version of the function and add the new function to the object with the original function name plus Async
a suffix.
Object.defineProperty(promiseify, "__esModule", {
value: true });
promiseify.default = promiseify;
module.exports = promiseify;
This code is mainly used to export promiseify
the function as a module. First, use Object.defineProperty
the method to promiseify
add 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.default
the property to promiseify
the function itself. In this way, when using import
syntax import, you can get promiseify
the function directly. Finally, use module.exports
export promiseify
the function as a module. require
In 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:
arguments
Object: An object automatically created inside a function to store parameters passed to the function.- DOM element list (NodeList): A collection of objects returned by querying DOM elements, such as
querySelectorAll
results obtained through methods. - String: Characters in a string can be accessed by index.
- 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:
- 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);
- Use the spread operator (Spread Operator): The spread operator (...) can spread an array-like object into a new array. For example:
var array = [...arrayLike];
- 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.slice
For example:var array = Array.prototype.slice.call(arrayLike);
- Usage
Array.prototype.concat()
: You can convert an array-like object to an array by callingArray.prototype.concat
the 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.