preface
Promise specification
- The realization principle of promise is mainly aimed at then method
1. Copy the cat
- 1.
Promise
Classes don’t have to worry about compatibility - 2. When
new Promise
Is passed an actuatorexecutor
This actuator is executed immediately - 3. The current
executor
Given two function arguments (resolve
.reject
) describes the state of the current promise - 4.
promise
There are three states waiting for success or failure - Default is wait
- If the call
resolve
Will lead to success - If the call
reject
Or the operation fails if an exception occurs - 5. Each
promise
Each instance has onethen
methods - 6.
promise
Once the state changes, it cannot be changed
let Promise = require('./promise.js')
let promise = new Promise((resolve, reject) = > {
resolve('ok')
})
promise.then((value) = >{
console.log("🚀 ~ success1." ", value)
}, (reason) = >{
console.log("🚀 ~ error1", reason)
})
promise.then((value) = >{
console.log("🚀 ~ success2", value)
}, (reason) = >{
console.log("🚀 ~ error2." ", reason)
})
Copy the code
/ * * *@description Three states *@const PENDING wait *@const FULFILLED successfully *@const REJECTED * / failure
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
this.status = PENDING; // Status Default wait
this.value = undefined; // Success value
this.reason = undefined; // Failed value
const resolve = (value) = > {
if (this.status === PENDING) {
this.value = value
this.status = FULFILLED
}
}
const reject = (reason) = > {
if (this.status === PENDING) {
this.reason = reason
this.status = REJECTED
}
}
try {
// The actuator passed in is executed immediately by default
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
// Successful callback
if (this.status === FULFILLED) {
onFulfilled(this.value)
}
// Failed callback
if (this.status === REJECTED) {
onRejected(this.reason)
}
}
}
module.exports = Promise
Copy the code
2. Asynchronous processing
- Publish and subscribe model
- How to handle asynchrony
- If you have
setTimeout
Is executed only after the current context finishes executingresolve()
let promise = new Promise((resolve, reject) = > {
setTimeout(() = >{
resolve('ok')},3000)
})
promise.then((value) = >{
console.log("🚀 ~ success1." ", value)
}, (reason) = >{
console.log("🚀 ~ error1", reason)
})
promise.then((value) = >{
console.log("🚀 ~ success2", value)
}, (reason) = >{
console.log("🚀 ~ error2." ", reason)
})
Copy the code
/ * * *@description Three states *@const PENDING wait *@const FULFILLED successfully *@const REJECTED * / failure
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
this.status = PENDING; // Status Default wait
this.value = undefined; // Success value
this.reason = undefined; // Failed value
this.onFulfilledCallbacks = []; // async callback method when the store succeeds
this.onRejectedCallbacks = []; // async callback method when storage fails
const resolve = (value) = > {
if (this.status === PENDING) {
this.value = value
this.status = FULFILLED
// Asynchronous problem publishing
this.onFulfilledCallbacks.forEach(fn= > fn())
}
}
const reject = (reason) = > {
if (this.status === PENDING) {
this.reason = reason
this.status = REJECTED
// Asynchronous problem publishing
this.onRejectedCallbacks.forEach(fn= > fn())
}
}
try {
// The actuator passed in is executed immediately by default
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
// Subscribe when there is an asynchronous problem
// The status is PENDING by default
if (this.status === PENDING) {
this.onFulfilledCallbacks.push(() = > {
onFulfilled(this.value)
})
this.onRejectedCallbacks.push(() = > {
onRejected(this.reason)
})
}
// Successful callback
if (this.status === FULFILLED) {
onFulfilled(this.value)
}
// Failed callback
if (this.status === REJECTED) {
onRejected(this.reason)
}
}
}
module.exports = Promise
Copy the code
3. Chain call (core)
- 1. Call
then
Will return aThe new promise
- 2.
then
The method returns a normal value as the result of the success of the next THEN - 3.
then
Error execution of the method in, will be the result of the next then failure - 4.
then
The method returns a promise according to the promiseresolve, reject
To deal with success or failure - 5. No matter
then
A walk succeeds or fails as long as it returns a normal valuethen
The success of the
let Promise = require('./promise.js')
let promise = new Promise((resolve, reject) = >{ resolve('Chain callback')})// then1
let promise2 = promise.then(
value= > { return value + '1' },
error= > { return error + '1'});// The first special case resolvePromise
// let promise2 = promise.then(
// value => { return promise2 },
// error => { return error + '1' }
// );
// The second special case resolvePromise
// let promise2 = promise.then(
// value => {
// // x could be a promise
// return new Promise((resolve,reject)=>{
// setTimeout(() => {
// resolve(new Promise((resolve,reject)=>{
// setTimeout(() => {
/ / resolve (' x is promise ');
/ /}, 1000);
/ /}))
/ /}, 1000)
/ /})
/ /},
// error => { return error + '1' }
// );
// then2
// 🚀 ~ success chain callback 1
promise2.then().then(null).then(
value= > { console.log("🚀 ~ success", value) },
error= > { console.log('🚀 ~ failure', error) }
);
// It can also be written like this
// promise.then(
// value => { return value + '1' },
// error => { return error + '1' }
// ).then(
/ / value = > {the console. The log (" 🚀 ~ success ", value)},
. / / the error = > {the console log (' 🚀 ~ failure, the error)}
// );
Copy the code
// chain call
// 1. Resolve nested callback (hell callback)
// 2. Synchronize the concurrency
// 3. Multiple asynchronous processing errors
/ * * *@description Three states *@const PENDING wait *@const FULFILLED successfully *@const REJECTED * / failure
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
this.status = PENDING; // Status Default wait
this.value = undefined; // Success value
this.reason = undefined; // Failed value
this.onFulfilledCallbacks = []; // async callback method when the store succeeds
this.onRejectedCallbacks = []; // async callback method when storage fails
const resolve = (value) = > {
// If value is a promise, then execute
if (value instanceof Promise) {
return value.then(resolve, reject)
}
if (this.status === PENDING) {
this.value = value
this.status = FULFILLED
// Asynchronous problem publishing
this.onFulfilledCallbacks.forEach(fn= > fn())
}
}
const reject = (reason) = > {
if (this.status === PENDING) {
this.reason = reason
this.status = REJECTED
// Asynchronous problem publishing
this.onRejectedCallbacks.forEach(fn= > fn())
}
}
try {
// The actuator passed in is executed immediately by default
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
// Nothing is passed continuously
// promise.then().then().then(...)
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v= > v;
onRejected = typeof onRejected === 'function' ? onRejected : error= > { throw error }
let promise2 = new Promise((resolve, reject) = > {
// Successful callback
// Take success as an example:
Resolve, reject, (try catch)
// 2. If a promise object is returned, use setTimeout to obtain the current promise2 object
if (this.status === FULFILLED) {
setTimeout(() = > {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)}// Failed callback
if (this.status === REJECTED) {
setTimeout(() = > {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)}// Subscribe when there is an asynchronous problem
// The status is PENDING by default
if (this.status === PENDING) {
this.onFulfilledCallbacks.push(() = > {
setTimeout(() = > {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)})this.onRejectedCallbacks.push(() = > {
setTimeout(() = > {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)})}})return promise2
}
}
/ * * *@description Process the result * returned by then@param Promise2 then returns a new promise object *@param X then parameter: ondepressing, onFulfilled, undefined * if there is no return@param Resolve Resolve * of promise2@param Reject Reject */ of promise2
function resolvePromise(promise2, x, resolve, reject) {
// The first special case resolvePromise
if (promise2 === x) { return reject(new TypeError('TypeError: Chaining cycle detected for Promise #
dead loop '
))}if ((typeof x === 'object'&& x ! = =null) | |typeof x === 'function') {
// Prevent someone else's written promise from failing after a successful call
let called = false;
try {
// The second special case resolvePromise
// It is possible that then is implemented via Object.defineProperty
let then = x.then;
if (typeof then === 'function') {
// Then the promise is used to prevent exceptions that trigger getters
then.call(x, y= > {
if (called) return;
called = true;
// Continue parsing until no promise
resolvePromise(promise2, y, resolve, reject)
}, r= > {
if (called) return;
called = true;
reject(r);
});
} else {
{} {then: {}}
resolve(x)
}
} catch (error) {
if (called) return;
called = true; reject(error); }}else {
/ / common valuesresolve(x); }}module.exports = Promise
Copy the code
Promise specification testing
- The installation
npm install promises-aplus-tests -g
- perform
promises-aplus-tests promise.js
- If there are no errors in the test
promise
Written in accordance with the specification - Only for
promise
In theresolve, reject
/ / promise. Ts file
// other code....
Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve,reject) = >{
dfd.resolve= resolve;
dfd.reject = reject;
});
return dfd;
}
module.exports = Promise
Copy the code
Other methods
Promise.resolve, Promise.reject, catch
class Promise {
// other code ...
// Promise.resolve
static resolve(value) {
return new Promise((resolve, reject) = > {
resolve(value)
})
}
static reject(value){
return new Promise((resolve,reject) = >{ reject(value); })}catch(errorFn){
return this.then(null,errorFn)
}
}
Copy the code
race
- Quickest to adopt
Promise.race
- In fact, every promise in the array has been executed
- The execution of one party is stopped immediately
- The main fastest has been revised
this.status
state - Others also perform but
If judgment
skip
class Promise {
// other code ...
static race(promises) {
return new Promise((resolve, reject) = > {
for (let i = 0; i < promises.length; i++) {
const p = promises[i];
if (p && typeof p.then === 'function') {
p.then(resolve, reject)
} else {
resolve(p)
}
}
})
}
}
Copy the code
let Promise = require('./promise.js')
let p1 = new Promise((resolve,reject) = >{
setTimeout(() = > {
resolve('success')},1000);
})
let p2 = new Promise((resolve,reject) = >{
setTimeout(() = > {
reject('failure')},500);
})
1 / / examples
// 'failed'
Promise.race([p1, p2]).then(
v= > console.log(v),
e= > console.log(e)
)
2 / / examples
/ / 1
Promise.race([p1, p2, 1]).then(
v= > console.log(v),
e= > console.log(e)
)
Copy the code
// make a timeout interrupt
let p3 = new Promise((resolve) = > {
setTimeout(() = >{
resolve('p3 success')},3000)})function warp(proParams) {
// Export interrupts
let abort;
let p = new Promise((resolve, reject) = > {
abort = reject
})
let result = Promise.race([p, proParams])
result.abort = abort
return result
}
let p3IsTimeOut = warp(p3)
p3IsTimeOut.then(
value= > console.log(value),
error= > console.log(error)
)
// end: 'one second out of time'
setTimeout(() = > {
p3IsTimeOut.abort('One second out of time')},1000)
Copy the code
finally
- Execute in failure or success
- And can continue
.then
- success
cb()
The returned value is not passed down or.then
thevalue
- Execution ends on failure
cb()
And throw an error (the error will continue to drop) - Why use
Promise.resolve
? - because
cb()
Execute if return valuePromise
object - Direct execution
val.then(resovle, reject)
And returnThe new promise
class Promise {
// other code ...
finally(cb) {
return this.then(
value= > {
return Promise.resolve(cb()).then(() = > value)
},
error= > {
return Promise.resolve(cb()).then(() = > { throw error })
}
)
}
}
Copy the code
let Promise = require('./source/promise3.js')
let p1 = new Promise((resolve,reject) = >{
setTimeout(() = > {
1 / / results
resolve('resolve: success')
2 / / results
// reject('reject: fail ')
}, 3000);
})
let p2 = p1.finally(() = > {
return new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve('123456');
}, 1000); })})1 / / results
/ / resolve: success
2 / / results
// 🚀 ~ catch reject: fails
p2.then(value= >{
console.log(value)
}).catch(error= > {
console.log("🚀 ~ catch", error)
})
Copy the code
In the node promisify
// a.txt this is a test fileCopy the code
const fs = require('fs')
// const { promisify } = require("util");
// const readFile = promisify(fs.readFile)
// This is a test file
// readFile('./a.txt', 'utf8').then(data => {
// console.log("🚀 ~ data", data)
// })
function promisify(fn) {
return function(. args){
return new Promise((resolve, reject) = >{ fn(... args,(err, data) = > {
if(err) returnreject(err); resolve(data); }}})})let p = promisify(fs.readFile)
// This is a test file
p('./a.txt'.'utf8').then(v= > console.log(v))
Copy the code