The following is a summary of pure dry handwritten version of the pen test code, do not thank you!

Promise variant

promise.first

The first returns a Promise of success

if (!Promise.first) {
  Promise.first = (promiseList) = > {
    return new Promise((resolve, reject) = > {
      let rejectNum = 0;
      const len = promiseList.length;

      promiseList.forEach((pr) = > {
        Promise.resolve(pr)
          .then(resolve)
          .catch(() = > {
            rejectNum++; // Record the number of reject
            if (rejectNum == len) {
              reject("all promise is reject"); }}); }); }); }; }Copy the code

promise.last

The last one returns a Promise of success

if (!Promise.last) {
  Promise.last = (promiseList) = > {
    return new Promise((resolve, reject) = > {
      let num = 0;
      const len = promiseList.length;
      let lastResult;

      const fn = () = > {
        if(num ! == len) {return;
        }
        lastResult ? resolve(lastResult) : reject("all promise is reject");
      };

      promiseList.forEach((pr) = > {
        Promise.resolve(pr)
          .then((data) = > {
            lastResult = data;
            num++;
            fn();
          })
          .catch(() = > {
            num++;
            fn();
          });
      });
    });
  };
}
Copy the code

promise.none

In contrast to promise.all, when all promises are rejected, promise.None becomes complete

if (!Promise.none) {
  Promise.none = (promiseList) = > {
    return Promise.all(
      promiseList.map((pr) = > {
        return new Promise((resolve, reject) = > {
          return Promise.resolve(pr).then(reject, resolve); }); })); }; }Copy the code

Promise.any

Only the results of all promises that enter the completed state are fetched, and those rejected are ignored

if (!Promise.any) {
  Promise.any = (promiseList) = > {
    return new Promise((resolve, reject) = > {
      const result = [];
      let num = 0;
      const len = promiseList.length;

      const fn = () = > {
        if (num == len) {
          result.length < 1 ? reject("all promise is reject") : resolve(result); }}; promiseList.forEach((pr) = > {
        Promise.resolve(pr)
          .then((data) = > {
            result.push(data);
            num++;
            fn();
          })
          .catch(() = > {
            num++;
            fn();
          });
      });
    });
  };
}
Copy the code

Promise.every

Return true if all promises are completed, false otherwise

if (!Promise.every) {
  Promise.every = (promiseList) = > {
    return new Promise((resolve, reject) = > {
      Promise.all(promiseList)
        .then(() = > Promise.resolve(true))
        .catch(() = > Promise.reject(false));
    });
  };
}
Copy the code

Promisify

The question

/ / before use

fs.readFile("./index.js".(err, data) = > {
  if(! err) {console.log(data.toString());
  }

  console.log(err);
});

// after using promisify

const readFile = promisify(fs.readFile);

readFile("./index.js")
  .then((data) = > {
    console.log(data.toString());
  })

  .catch((err) = > {
    console.log("error:", err);
  });
Copy the code

solution

function promisify(fn) {
  return (. args) = > {
    return new Promise((resolve, reject) = > {
      fn.apply(this, [
        ...args,
        (err, data) = > {
          if(! err) {return resolve(data);
          }

          returnreject(err); },]); }); }; }Copy the code

Sleep simulation

async function sleep(sleepTime) {
  return new Promise((resolve) = > {
    setTimeout(resolve, sleepTime);
  });
}
Copy the code

JS implements an asynchronous scheduler with concurrency limits

The question

JS implements an asynchronous Scheduler Scheduler with concurrency limits, ensuring that up to 10 tasks can be run at the same time.

Class Scheduler{
	constructor(max){}
	run(callback){/ *... * /}}let s = new Scheduler(10);
s.run(async() = > {/* some async operations */
});
Copy the code

solution

Class Scheduler{
	COUNT = 0;
	LIST = [];
	constructor(max){
		this.LIMIT = 10;
	}
	async run(callback){
		if(this.COUNT >= this.LIMIT){
			// With await, as long as resolve is not done, the code execution will block here
			await new Promise((resolve) = > {
				this.list.push(resolve);
			});

		}
		this.COUNT++;

		const result = await callback();

		this.COUNT--;

		if(this.list.length > 0) {this.list.shift()(); // Unlock code is blocked
		}

		returnresult; }}let s = new Scheduler(10);
s.run(async() = > {/* some async operations */
});
s.run(async() = > {/* some async operations */
});
s.run(async() = > {/* some async operations */
});
Copy the code

Write a Promise

Key points of Promise

  • A Promise is a class that takes an executor and executes it immediately
  • Promises come in three states
    • Pending waiting for
    • Fulfilled complete
    • The rejected failure
  • The state can only change once, not backwards.
    • pending -> fulfilled
    • pending -> rejected
  • Promise uses the resolve and reject functions to change the state
  • Then method makes internal state judgment and executes corresponding method
  • There are static methods promise.resolve and promise.reject

Handwritten edition

// State constant
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class Promise {
  state = PENDING;
  value = undefined;
  reason = undefined;
  onResolveCallback = [];
  onRejectCallback = [];

  constructor(executor) {
    try {
      executor(this.resolve, this.reject);
    } catch (err) {
      this.reject(err); }}resolve(data) {
    if (this.state ! == PENDING) {return;
    }
    this.state = FULFILLED;
    this.value = data;

    while (this.onResolveCallback.length > 0) {
      const currentResolve = this.onResolveCallback.shift();
      currentResolve(this.value); }}reject(err) {
    if (this.state ! == PENDING) {return;
    }
    this.state = REJECTED;
    this.reason = err;

    while (this.onRejectCallback.length > 0) {
      const currentReject = this.onRejectCallback.shift();
      currentReject(this.reason); }}static resolve(param) {
    // Param is a Promise object that returns directly
    if (param instanceof Promise) {
      return param;
    }

    // Change to normal Promise
    return new Promise((resolve) = > {
      resolve(param);
    });
  }
  static reject(reason) {
    return new Promise((resolve, reject) = > {
      reject(reason);
    });
  }
  catch(fn) {
    if (this.state == REJECTED) {
      typeof fn == "function" && fn(this.reason); }}then(resolve, reject) {
    const realResolve =
      typeof resolve == "function" ? resolve : (value) = > value;
    const realReject =
      typeof reject == "function"
        ? reject
        : (reason) = > {
            throw reason;
          };

    // a chain call that returns a new Promise instance

    const newPromise = new Promise((resolve, reject) = > {
      // Create a microtask and wait for the Promise initialization to complete

      const microResolve = () = > {
        queueMicrotask(() = > {
          try {
            const x = realResolve(this.value);
            resolvePromise(newPromise, x, resolve, reject);
          } catch(err) { reject(err); }}); };const microReject = () = > {
        queueMicrotask(() = > {
          try {
            const x = realReject(this.reason);
            resolvePromise(newPromise, x, reasolve, reject);
          } catch(err) { reject(err); }}); };if (this.state == FULFILLED) {
        return microResolve(this.value);
      }
      if (this.state == REJECTED) {
        return microReject(this.reason);
      }
      if (this.state == PENDING) {
        this.onResolveCallback.push(microResolve);
        this.onRejectCallback.push(microReject); }});returnnewPromise; }}function resolvePromise(newPromise, x, resolve, reject) {
  if (newPromise == x) {
    return reject(new Error("Circular reference"));
  }

  if (x instanceof Promise) {
    x.then(resolve, reject);
  } else{ resolve(x); }}Copy the code

Simulate the implementation of BIND

ES5 version

Function.prototype.bind =
  Function.prototype.bind ||
  function (context) {
    if (typeof this! = ="function") {
      throw new Error("can't bind");
    }

    let self = this;
    let args = Array.prototype.slice(arguments.1); // Cache parameters

    const fnOP = function () {};

    const bound = function () {
      let innerArgs = Array.prototype.slice(arguments);

      return self.apply(
        this instanceof fnOP ? this : context,
        args.concat(innerArgs)
      );
    };

    fnOP.prototype = this.prototype;
    bound.prototype = new fnOP();

    return bound;
  };
Copy the code

ES6 version

Function.prototype.bind =
  Function.prototype.bind ||
  function () {
    if (typeof this! = ="function") {
      throw new Error("can't bind");
    }

    const args = Array.from(arguments);
    const context = args.shift();
    const self = this;

    const fnOP = Object.create(this.prototype);

    const fn = function () {
      const innerArgs = Array.from(arguments);
      return self.apply(
        this instanceof fnOP ? this : context,
        args.concat(innerArgs)
      );
    };

    fn.prototype = fnOP;

    return fn;
  };
Copy the code

Simulate the implementation of new

function Otaku(name, age) {
  this.name = name;
  this.age = age;

  this.habit = "Games";
}

Otaku.prototype.strength = 60;

Otaku.prototype.sayYourName = function () {
  console.log("I am " + this.name);
};

/ / call
myNew(Otaku, "Kevin"."18");

console.log(person.name); // Kevin
console.log(person.habit); // Games
console.log(person.strength); / / 60

person.sayYourName(); // I am Kevin
Copy the code
/ / implementation
function myNew(fn, ... args) {
  const obj = Object.create(fn.prototype);

  const ret = fn.apply(obj, args); // Ret may be null

  return typeof ret === "object" ? ret || obj : obj;
}
Copy the code

Deep copy

Deep copy note

  • Note the types, the seven basic types:boolean,string,number,undefinednull,Symbol,BigInt
  • ObjectTypes of possible Object. The prototype. ToString. (call) :
    • [object Object]
    • [object Function] – typeof function == function
    • [object Null]
    • [object Array]
    • [object RegExp]

solution

function deepCopy(data, hash = new WeakMap(a)) {
  if (typeofdata ! = ="object" || data == null) {
    return data;
  }
  // Check whether the passed object to be copied already exists in the hash to avoid loop references
  if (hash.has(data)) {
    return hash.get(data);
  }

  const newData = Array.isArray(data) ? [] : {};
  const dataKeys = Object.keys(data);
  dataKeys.forEach((key) = > {
    const current = data[key];
    const typeString = Object.prototype.toString.call(current).toLowerCase();

    if (typeofcurrent ! = ="object" || current == null) {
      // Basic type
      newData[key] = current;
      return;
    }

    switch (typeString) {
      case "[object array]":
        newData[key] = [...deepCopy(current, hash)];
        break;
      case "[object set]":
        newData[key] = new Set([...current.values()]);
        break;
      case "[object map]":
        newData[key] = new Map([...current]);
        break;
      default:
        // Common objects perform recursive operationshash.set(data, data); newData[key] = deepCopy(current, hash); }});return newData;
}
Copy the code

Array to heavy

ES6 Set

const uniqueArr = [...new Set(arr)];
const uniqueArr = Array.from(new Set(arr));
Copy the code

reduce

function unique(arr) {
  // Sort first, if repeated, the content of the previous subscript is the same
  return arr.sort().reduce((acc, current) = > {
    if (acc.length == 0 || acc[acc.length - 1] !== current) {
      acc.push(current);
    }
    returnacc; } []); }Copy the code

filter

function unique(arr) {
  return arr.filter((element, index, array) = > {
    return array.indexOf(element) == index;
  });
}
Copy the code

Flattening an array

Flattening is done using the Reduce method

function flattenDeep(arr) {
  return Array.isArray(arr)
    ? arr.reduce((acc, current) = > {
        return [...acc, ...flattenDeep(current)];
      }, [])
    : [arr];
}
Copy the code

Simulation of the stack

function flattenDeep(arr) {
  const stack = [...arr]; // Copy it flat to stack
  const result = [];

  while (stack.length) {
    // Fetch the trailing value
    const current = stack.pop();
    if (Array.isArray(current)) {
      // If the value is an array, push the stack again after flatteningstack.push(... current); }else {
      // If the end is a normal value, store resultresult.unshift(current); }}return result;
}
Copy the code

Currie,

function curry(fn) {
  return function curried(. args) {
    if (args.length >= fn.length) {
      // The passed parameter overrides all the visible parameters
      fn.apply(this, args);
    } else {
      return function (. args2) {
        return curried.apply(this, args.concat(args2)); }; }}; }Copy the code

Image stabilization

function debounce(fn, wait) {
  let timer = null;
  return () = > {
    clearTimeout(timer);
    timer = setTimeout(() = > {
      fn.apply(this.Array.from(arguments));
    }, wait);
  };
}
Copy the code

The throttle

function throttle(fn, wait) {
  let timer = null;

  return () = > {
    if(timer ! = =null) {
      return;
    }

    timer = setTimeout(() = > {
      fn.apply(this.Array.from(arguments));
      timer = null;
    }, wait);
  };
}
Copy the code