Book to back

Catch method and implementation of exception penetration

In this section we implement three small details:

  1. Implementation of the catch method
  2. Abnormal penetration
  3. Value passed

Implementation of the catch method

It is used to catch errors before processing. The implementation is also very simple

Prototype. Catch = function (onRejected){return this. Then (undefined,onRejected)}Copy the code

All we need to do is call the then method, because the catch method doesn’t need to handle success, only failure, so we pass in a failed callback.

Abnormal penetration

What is abnormal penetration? Consider the official example:

let p = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        reject("error");
    },100)
});
const result = p.then(value=>{
   console.log(111)
}).then(value=>{
    console.log(222)
}).then(value=>{
    console.log(333)
}).catch(reason=>{
    console.log(reason);
})
//error
Copy the code

You can see that the error reported has reached the catch callback. When we call our own call, we will report the following error:

TypeError: type is not a function
    at callback (<anonymous>:65:30)
    at Object.onRejected (<anonymous>:101:21)
Copy the code

In the call

onRejected:function (){
    callback(onRejected);
}
Copy the code

When an error occurs? Type is not a function the onRejected callback does not create. So we need to give it a default:

Prototype. Then = function (onResolved,onRejected){const self = this; // Check if(Typeof onRejected! == 'function'){ onRejected = reason => { throw reason } } //.....Copy the code

When this method is added, if an error is found, its processing is backward until the end.

Test cases:

let p = new PromiseA((resolve,reject)=>{
    setTimeout(()=>{
        reject("error");
    },100)
});
const result = p.then(value=>{
   console.log(111)
}).then(value=>{
    console.log(222)
}).then(value=>{
    console.log(333)
}).catch(reason=>{
    console.log(reason);
})
//error
Copy the code

Or throw an error in between:

let p = new PromiseA((resolve,reject)=>{ setTimeout(()=>{ resolve("ok"); }, 100)}); const result = p.then(value=>{ console.log(111) }).then(value=>{ throw "error" }).then(value=>{ console.log(333) }).catch(reason=>{ console.log(reason); }) // output //111 //errorCopy the code

Value passed

In fact, the effect is that the then method can be passed without writing the callback function, so similar to the above, we can add a default method.

Prototype. Then = function (onResolved,onRejected){const self = this; // Check if(Typeof onRejected! = = 'function') {onRejected = "reason = > {throw reason}} / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- code changes -- -- -- -- -- the if (typeof onResolved! == "function"){ onResolved = value => value; } //-------------- where to modify the code ---------- //...Copy the code

Test cases:

let p = new PromiseA((resolve,reject)=>{ setTimeout(()=>{ resolve("ok"); }, 100)}); Const result = p.teng ().then(value=>{console.log(value)}) // OkCopy the code

You can see that our intermediate then method does not set the callback function, but still passes the value later.

13. Promise. Resolve the encapsulation

The property of this method, documented in the previous tip, returns a Promise object.

The state of the Promise object depends on the parameters passed to it. Does this sound familiar? Yeah, it’s the same thing.

  1. If it returns a non-promise object, such as 123, OK, or undefined, it will, by default, execute a successful Promise object,
  2. If this object is successful, then the external result is successful, and if it fails, then the external result is failed.
  3. If an error is thrown, the external object fails.

So we can do this:

Resolve = function (value){// Return Promise return new PromiseA((resolve,reject)=>{try{if(value instanceof PromiseA){ value.then(v=>{ resolve(v); },r=>{ reject(r); }) }else{ resolve(value); } }catch (e){ reject(e); }})}Copy the code

Test cases:

let p = PromiseA.resolve( new PromiseA((resolve,reject)=>{ reject("error"); })); let p1 = PromiseA.resolve(new PromiseA((resolve,reject)=>{ resolve("OK"); })) let p2 = PromiseA.resolve(111); Log (p) console.log(p1) console.log(p2) // Error PromiseA {PromiseState: 'rejected', PromiseResult: 'error', callbacks: [] } PromiseA { PromiseState: 'fulfilled', PromiseResult: 'OK', callbacks: [] } PromiseA { PromiseState: 'fulfilled', PromiseResult: 111, callbacks: [] }Copy the code

13. Promise. Reject the encapsulation

The difference between resolve and resolve is that its Promise that returns a result is a failure in any case.

Reject = function (value){// Return Promise return new reject((resolve,reject)=>{reject(value)}) }Copy the code

14.Promise. All encapsulation implementation

What are its characteristics? It takes an array of Promise objects. A promise will only succeed if all of its promise objects succeed, but if any of them fail, the result will fail.

Here’s how to do it:

All = function (Promise){// return new PromiseA((resolve,reject)=>{// let count = 0; let arr = []; for(let i = 0; i<promises.length; I ++){promises[I]. Then (v=>{// Every promise is successful; // Store the result of the current Promise object's success into an array // arr.push(v); arr[i] = v; if(count === promises.length){ resolve(arr); } },r=>{ reject(r); }); }})}Copy the code

Test case: Success case

let p = PromiseA.resolve("ok");
let p1 = PromiseA.resolve("111");
let p2 = new PromiseA((resolve,reject)=>{
    setTimeout(()=>{
        resolve("ccc")
    },1000)
})

let p3 = PromiseA.all([p,p1,p2]);
p3.then((data)=>{
    console.log(data);
})
Copy the code

Output result:

[ 'ok', '111', 'ccc' ]
Copy the code

Test case: Failure situation

let p = PromiseA.resolve("ok"); let p1 = PromiseA.resolve("111"); let p2 = new PromiseA((resolve,reject)=>{ setTimeout(()=>{ reject("error"); },1000) }) let p3 = PromiseA.race([p,p1,p2]); P3. Catch (e=>{console.log(e)}) // output //errorCopy the code

15 Promise.race encapsulation

It has the property that if one of them succeeds, it succeeds and returns the result, if one of them fails, it fails, returns the result of failure, and so on. Call without counting directly to result.

PromiseA.race = function (promises){
    return new PromiseA((resolve,reject)=>{
        for(let i = 0;i<promises.length;i++){
            promises[i].then(v=>{
                resolve(v);
            },r=>{
                reject(r);
            });
        }
    })
}

Copy the code

Test cases:

let p = PromiseA.resolve("ok"); let p1 = PromiseA.resolve("111"); let p2 = new PromiseA((resolve,reject)=>{ setTimeout(()=>{ reject("111"); },1000) }) let p3 = PromiseA.race([p,p1,p2]); P3. then(v=>{console.log(v)}) // Output OKCopy the code

The callback function is executed asynchronously

Here’s the complete code:

Function PromiseA(executor){// Add attribute this.PromiseState = "pending"; this.PromiseResult = null; this.callbacks = []; // Prestore this value of the instance object const self = this; Function resolve(data){if(self.promisestate! == "pending"){ return ; // this is a big pity; // this is a big pity. //2. Set the result value of the object (PromiseResult) self.promiseresult = data; QueueMicrotask (()=> {// Call the successful callback self.callbacks.foreach (item => {item.onresolved (data); If (self.promisestestate!){if(self.promisestestate! == "pending"){ return ; } //1. Modify the state of the object (PromiseState) self.PromiseState = "Rejected "; //2. Set the result value of the object (PromiseResult) self.promiseresult = data; QueueMicrotask (()=> {// Call self.callbacks. ForEach (item => {item.onRejected(data); // call executor(resolve,reject); }catch (e){reject(e) {reject(e) {reject(e) {reject(e); Prototype = function (onResolved,onRejected){const self = this; // Check if(Typeof onRejected! == 'function'){ onRejected = reason => { throw reason } } if(typeof onResolved ! == "function"){ onResolved = value => value; Return new PromiseA((resolve,reject)=>{function callback(type){ try{ let result = type(self.PromiseResult); If (result instanceof PromiseA){// If (result instanceof PromiseA){// If (result instanceof PromiseA){ // The Promise object will call onResolved when it fails onRejected result.then(v=>{// The Promise object will call resolve when it fails onRejected result.then(v=>{// resolve(v); },r=>{ reject(r); Resolve (result); resolve(result); resolve(result); } }catch (e){ reject(e); } // call the successful callback function if(self.PromiseState === "depressing "){queueMicrotask(()=> {callback(onResolved); If (self.promisestate === "rejected"){queueMicrotask(()=> {callback(onRejected); If (self.promisestate === "pending"){// Save self.callbacks. Push ({onResolved:function (){ queueMicrotask(()=> { callback(onResolved); }); }, onRejected:function (){ queueMicrotask(()=> { callback(onRejected); }}})); Prototype. Catch = function (onRejected){return this. Then (onRejected){return this Resolve = function (value){// Return Promise return new PromiseA((resolve,reject)=>{try{if(value) instanceof PromiseA){ value.then(v=>{ resolve(v); },r=>{ reject(r); }) }else{ resolve(value); } }catch (e){ reject(e); Reject = function (value){return Promise return new PromiseA((resolve,reject)=>{try{ reject(value) }catch (e){ reject(e); }})} / / add all methods PromiseA. All = function (promises) {/ / return the result for the Promise of object return new PromiseA ((resolve, reject) = > {/ / traverse let count = 0; let arr = []; for(let i = 0; i<promises.length; I ++){promises[I]. Then (v=>{// Every promise is successful; // Store the result of the current Promise object's success into an array // arr.push(v); arr[i] = v; if(count === promises.length){ resolve(arr); } },r=>{ reject(r); }); PromiseA = function (promise){return new PromiseA((resolve,reject)=>{for(let I = 0; i<promises.length; i++){ promises[i].then(v=>{ resolve(v); },r=>{ reject(r); }); }})}Copy the code

Test cases:

let p = new PromiseA((resolve,reject)=>{ console.log('111') resolve("222") }) console.log(333) p.then((value)=>{ Console. log(value)}) 111 333 222 is displayedCopy the code